summaryrefslogtreecommitdiffstats
path: root/devtools/client/shared/components/test
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /devtools/client/shared/components/test
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'devtools/client/shared/components/test')
-rw-r--r--devtools/client/shared/components/test/browser/.eslintrc.js6
-rw-r--r--devtools/client/shared/components/test/browser/browser.ini7
-rw-r--r--devtools/client/shared/components/test/browser/browser_notification_box_basic.js36
-rw-r--r--devtools/client/shared/components/test/mochitest/.eslintrc.js6
-rw-r--r--devtools/client/shared/components/test/mochitest/chrome.ini51
-rw-r--r--devtools/client/shared/components/test/mochitest/head.js217
-rw-r--r--devtools/client/shared/components/test/mochitest/test_HSplitBox_01.html126
-rw-r--r--devtools/client/shared/components/test/mochitest/test_frame_01.html309
-rw-r--r--devtools/client/shared/components/test/mochitest/test_notification_box_01.html108
-rw-r--r--devtools/client/shared/components/test/mochitest/test_notification_box_02.html70
-rw-r--r--devtools/client/shared/components/test/mochitest/test_notification_box_03.html84
-rw-r--r--devtools/client/shared/components/test/mochitest/test_reps_array.html259
-rw-r--r--devtools/client/shared/components/test/mochitest/test_reps_attribute.html56
-rw-r--r--devtools/client/shared/components/test/mochitest/test_reps_comment-node.html80
-rw-r--r--devtools/client/shared/components/test/mochitest/test_reps_date-time.html79
-rw-r--r--devtools/client/shared/components/test/mochitest/test_reps_document.html56
-rw-r--r--devtools/client/shared/components/test/mochitest/test_reps_element-node.html341
-rw-r--r--devtools/client/shared/components/test/mochitest/test_reps_event.html300
-rw-r--r--devtools/client/shared/components/test/mochitest/test_reps_function.html206
-rw-r--r--devtools/client/shared/components/test/mochitest/test_reps_grip-array.html707
-rw-r--r--devtools/client/shared/components/test/mochitest/test_reps_grip-map.html405
-rw-r--r--devtools/client/shared/components/test/mochitest/test_reps_grip.html887
-rw-r--r--devtools/client/shared/components/test/mochitest/test_reps_infinity.html73
-rw-r--r--devtools/client/shared/components/test/mochitest/test_reps_long-string.html125
-rw-r--r--devtools/client/shared/components/test/mochitest/test_reps_nan.html48
-rw-r--r--devtools/client/shared/components/test/mochitest/test_reps_null.html44
-rw-r--r--devtools/client/shared/components/test/mochitest/test_reps_number.html97
-rw-r--r--devtools/client/shared/components/test/mochitest/test_reps_object-with-text.html54
-rw-r--r--devtools/client/shared/components/test/mochitest/test_reps_object-with-url.html60
-rw-r--r--devtools/client/shared/components/test/mochitest/test_reps_object.html225
-rw-r--r--devtools/client/shared/components/test/mochitest/test_reps_promise.html333
-rw-r--r--devtools/client/shared/components/test/mochitest/test_reps_regexp.html51
-rw-r--r--devtools/client/shared/components/test/mochitest/test_reps_string.html79
-rw-r--r--devtools/client/shared/components/test/mochitest/test_reps_stylesheet.html54
-rw-r--r--devtools/client/shared/components/test/mochitest/test_reps_symbol.html77
-rw-r--r--devtools/client/shared/components/test/mochitest/test_reps_text-node.html115
-rw-r--r--devtools/client/shared/components/test/mochitest/test_reps_undefined.html47
-rw-r--r--devtools/client/shared/components/test/mochitest/test_reps_window.html58
-rw-r--r--devtools/client/shared/components/test/mochitest/test_sidebar_toggle.html56
-rw-r--r--devtools/client/shared/components/test/mochitest/test_stack-trace.html102
-rw-r--r--devtools/client/shared/components/test/mochitest/test_tabs_accessibility.html79
-rw-r--r--devtools/client/shared/components/test/mochitest/test_tabs_menu.html81
-rw-r--r--devtools/client/shared/components/test/mochitest/test_tree_01.html64
-rw-r--r--devtools/client/shared/components/test/mochitest/test_tree_02.html45
-rw-r--r--devtools/client/shared/components/test/mochitest/test_tree_03.html46
-rw-r--r--devtools/client/shared/components/test/mochitest/test_tree_04.html128
-rw-r--r--devtools/client/shared/components/test/mochitest/test_tree_05.html83
-rw-r--r--devtools/client/shared/components/test/mochitest/test_tree_06.html320
-rw-r--r--devtools/client/shared/components/test/mochitest/test_tree_07.html64
-rw-r--r--devtools/client/shared/components/test/mochitest/test_tree_08.html51
-rw-r--r--devtools/client/shared/components/test/mochitest/test_tree_09.html77
-rw-r--r--devtools/client/shared/components/test/mochitest/test_tree_10.html52
-rw-r--r--devtools/client/shared/components/test/mochitest/test_tree_11.html92
53 files changed, 7276 insertions, 0 deletions
diff --git a/devtools/client/shared/components/test/browser/.eslintrc.js b/devtools/client/shared/components/test/browser/.eslintrc.js
new file mode 100644
index 000000000..76904829d
--- /dev/null
+++ b/devtools/client/shared/components/test/browser/.eslintrc.js
@@ -0,0 +1,6 @@
+"use strict";
+
+module.exports = {
+ // Extend from the shared list of defined globals for mochitests.
+ "extends": "../../../../../.eslintrc.mochitests.js",
+};
diff --git a/devtools/client/shared/components/test/browser/browser.ini b/devtools/client/shared/components/test/browser/browser.ini
new file mode 100644
index 000000000..9db9eca66
--- /dev/null
+++ b/devtools/client/shared/components/test/browser/browser.ini
@@ -0,0 +1,7 @@
+[DEFAULT]
+tags = devtools
+subsuite = devtools
+support-files =
+ !/devtools/client/framework/test/shared-head.js
+
+[browser_notification_box_basic.js]
diff --git a/devtools/client/shared/components/test/browser/browser_notification_box_basic.js b/devtools/client/shared/components/test/browser/browser_notification_box_basic.js
new file mode 100644
index 000000000..b7c6a669b
--- /dev/null
+++ b/devtools/client/shared/components/test/browser/browser_notification_box_basic.js
@@ -0,0 +1,36 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* 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";
+
+/* import-globals-from ../../../../framework/test/shared-head.js */
+
+Services.scriptloader.loadSubScript(
+ "chrome://mochitests/content/browser/devtools/client/framework/test/shared-head.js", this);
+
+const TEST_URI = "data:text/html;charset=utf-8,Test page";
+
+/**
+ * Basic test that checks existence of the Notification box.
+ */
+add_task(function* () {
+ info("Test Notification box basic started");
+
+ let toolbox = yield openNewTabAndToolbox(TEST_URI, "webconsole");
+
+ // Append a notification
+ let notificationBox = toolbox.getNotificationBox();
+ notificationBox.appendNotification(
+ "Info message",
+ "id1",
+ null,
+ notificationBox.PRIORITY_INFO_HIGH
+ );
+
+ // Verify existence of one notification.
+ let parentNode = toolbox.doc.getElementById("toolbox-notificationbox");
+ let nodes = parentNode.querySelectorAll(".notification");
+ is(nodes.length, 1, "There must be one notification");
+});
diff --git a/devtools/client/shared/components/test/mochitest/.eslintrc.js b/devtools/client/shared/components/test/mochitest/.eslintrc.js
new file mode 100644
index 000000000..677cbb424
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/.eslintrc.js
@@ -0,0 +1,6 @@
+"use strict";
+
+module.exports = {
+ // Extend from the shared list of defined globals for mochitests.
+ "extends": "../../../../../.eslintrc.mochitests.js"
+};
diff --git a/devtools/client/shared/components/test/mochitest/chrome.ini b/devtools/client/shared/components/test/mochitest/chrome.ini
new file mode 100644
index 000000000..27a4be137
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/chrome.ini
@@ -0,0 +1,51 @@
+[DEFAULT]
+support-files =
+ head.js
+
+[test_frame_01.html]
+[test_HSplitBox_01.html]
+[test_notification_box_01.html]
+[test_notification_box_02.html]
+[test_notification_box_03.html]
+[test_reps_array.html]
+[test_reps_attribute.html]
+[test_reps_comment-node.html]
+[test_reps_date-time.html]
+[test_reps_document.html]
+[test_reps_element-node.html]
+[test_reps_event.html]
+[test_reps_function.html]
+[test_reps_grip.html]
+[test_reps_grip-array.html]
+[test_reps_grip-map.html]
+[test_reps_infinity.html]
+[test_reps_long-string.html]
+[test_reps_nan.html]
+[test_reps_null.html]
+[test_reps_number.html]
+[test_reps_object.html]
+[test_reps_object-with-text.html]
+[test_reps_object-with-url.html]
+[test_reps_promise.html]
+[test_reps_regexp.html]
+[test_reps_string.html]
+[test_reps_stylesheet.html]
+[test_reps_symbol.html]
+[test_reps_text-node.html]
+[test_reps_undefined.html]
+[test_reps_window.html]
+[test_sidebar_toggle.html]
+[test_stack-trace.html]
+[test_tabs_accessibility.html]
+[test_tabs_menu.html]
+[test_tree_01.html]
+[test_tree_02.html]
+[test_tree_03.html]
+[test_tree_04.html]
+[test_tree_05.html]
+[test_tree_06.html]
+[test_tree_07.html]
+[test_tree_08.html]
+[test_tree_09.html]
+[test_tree_10.html]
+[test_tree_11.html]
diff --git a/devtools/client/shared/components/test/mochitest/head.js b/devtools/client/shared/components/test/mochitest/head.js
new file mode 100644
index 000000000..b66b72814
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/head.js
@@ -0,0 +1,217 @@
+/* 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/. */
+/* eslint no-unused-vars: [2, {"vars": "local"}] */
+
+"use strict";
+
+var { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
+
+var { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
+var { Assert } = require("resource://testing-common/Assert.jsm");
+var { gDevTools } = require("devtools/client/framework/devtools");
+var { BrowserLoader } = Cu.import("resource://devtools/client/shared/browser-loader.js", {});
+var promise = require("promise");
+var defer = require("devtools/shared/defer");
+var Services = require("Services");
+var { DebuggerServer } = require("devtools/server/main");
+var { DebuggerClient } = require("devtools/shared/client/main");
+var DevToolsUtils = require("devtools/shared/DevToolsUtils");
+var flags = require("devtools/shared/flags");
+var { Task } = require("devtools/shared/task");
+var { TargetFactory } = require("devtools/client/framework/target");
+var { Toolbox } = require("devtools/client/framework/toolbox");
+
+flags.testing = true;
+var { require: browserRequire } = BrowserLoader({
+ baseURI: "resource://devtools/client/shared/",
+ window
+});
+
+let ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
+let React = browserRequire("devtools/client/shared/vendor/react");
+var TestUtils = React.addons.TestUtils;
+
+var EXAMPLE_URL = "http://example.com/browser/browser/devtools/shared/test/";
+
+function forceRender(comp) {
+ return setState(comp, {})
+ .then(() => setState(comp, {}));
+}
+
+// All tests are asynchronous.
+SimpleTest.waitForExplicitFinish();
+
+function onNextAnimationFrame(fn) {
+ return () =>
+ requestAnimationFrame(() =>
+ requestAnimationFrame(fn));
+}
+
+function setState(component, newState) {
+ return new Promise(resolve => {
+ component.setState(newState, onNextAnimationFrame(resolve));
+ });
+}
+
+function setProps(component, newProps) {
+ return new Promise(resolve => {
+ component.setProps(newProps, onNextAnimationFrame(resolve));
+ });
+}
+
+function dumpn(msg) {
+ dump(`SHARED-COMPONENTS-TEST: ${msg}\n`);
+}
+
+/**
+ * Tree
+ */
+
+var TEST_TREE_INTERFACE = {
+ getParent: x => TEST_TREE.parent[x],
+ getChildren: x => TEST_TREE.children[x],
+ renderItem: (x, depth, focused) => "-".repeat(depth) + x + ":" + focused + "\n",
+ getRoots: () => ["A", "M"],
+ getKey: x => "key-" + x,
+ itemHeight: 1,
+ onExpand: x => TEST_TREE.expanded.add(x),
+ onCollapse: x => TEST_TREE.expanded.delete(x),
+ isExpanded: x => TEST_TREE.expanded.has(x),
+};
+
+function isRenderedTree(actual, expectedDescription, msg) {
+ const expected = expectedDescription.map(x => x + "\n").join("");
+ dumpn(`Expected tree:\n${expected}`);
+ dumpn(`Actual tree:\n${actual}`);
+ is(actual, expected, msg);
+}
+
+// Encoding of the following tree/forest:
+//
+// A
+// |-- B
+// | |-- E
+// | | |-- K
+// | | `-- L
+// | |-- F
+// | `-- G
+// |-- C
+// | |-- H
+// | `-- I
+// `-- D
+// `-- J
+// M
+// `-- N
+// `-- O
+var TEST_TREE = {
+ children: {
+ A: ["B", "C", "D"],
+ B: ["E", "F", "G"],
+ C: ["H", "I"],
+ D: ["J"],
+ E: ["K", "L"],
+ F: [],
+ G: [],
+ H: [],
+ I: [],
+ J: [],
+ K: [],
+ L: [],
+ M: ["N"],
+ N: ["O"],
+ O: []
+ },
+ parent: {
+ A: null,
+ B: "A",
+ C: "A",
+ D: "A",
+ E: "B",
+ F: "B",
+ G: "B",
+ H: "C",
+ I: "C",
+ J: "D",
+ K: "E",
+ L: "E",
+ M: null,
+ N: "M",
+ O: "N"
+ },
+ expanded: new Set(),
+};
+
+/**
+ * Frame
+ */
+function checkFrameString({
+ el, file, line, column, source, functionName, shouldLink, tooltip
+}) {
+ let $ = selector => el.querySelector(selector);
+
+ let $func = $(".frame-link-function-display-name");
+ let $source = $(".frame-link-source");
+ let $sourceInner = $(".frame-link-source-inner");
+ let $filename = $(".frame-link-filename");
+ let $line = $(".frame-link-line");
+
+ is($filename.textContent, file, "Correct filename");
+ is(el.getAttribute("data-line"), line ? `${line}` : null, "Expected `data-line` found");
+ is(el.getAttribute("data-column"),
+ column ? `${column}` : null, "Expected `data-column` found");
+ is($sourceInner.getAttribute("title"), tooltip, "Correct tooltip");
+ is($source.tagName, shouldLink ? "A" : "SPAN", "Correct linkable status");
+ if (shouldLink) {
+ is($source.getAttribute("href"), source, "Correct source");
+ }
+
+ if (line != null) {
+ let lineText = `:${line}`;
+ if (column != null) {
+ lineText += `:${column}`;
+ }
+
+ is($line.textContent, lineText, "Correct line number");
+ } else {
+ ok(!$line, "Should not have an element for `line`");
+ }
+
+ if (functionName != null) {
+ is($func.textContent, functionName, "Correct function name");
+ } else {
+ ok(!$func, "Should not have an element for `functionName`");
+ }
+}
+
+function renderComponent(component, props) {
+ const el = React.createElement(component, props, {});
+ // By default, renderIntoDocument() won't work for stateless components, but
+ // it will work if the stateless component is wrapped in a stateful one.
+ // See https://github.com/facebook/react/issues/4839
+ const wrappedEl = React.DOM.span({}, [el]);
+ const renderedComponent = TestUtils.renderIntoDocument(wrappedEl);
+ return ReactDOM.findDOMNode(renderedComponent).children[0];
+}
+
+function shallowRenderComponent(component, props) {
+ const el = React.createElement(component, props);
+ const renderer = TestUtils.createRenderer();
+ renderer.render(el, {});
+ return renderer.getRenderOutput();
+}
+
+/**
+ * Test that a rep renders correctly across different modes.
+ */
+function testRepRenderModes(modeTests, testName, componentUnderTest, gripStub) {
+ modeTests.forEach(({mode, expectedOutput, message}) => {
+ const modeString = typeof mode === "undefined" ? "no mode" : mode;
+ if (!message) {
+ message = `${testName}: ${modeString} renders correctly.`;
+ }
+
+ const rendered = renderComponent(componentUnderTest.rep, { object: gripStub, mode });
+ is(rendered.textContent, expectedOutput, message);
+ });
+}
diff --git a/devtools/client/shared/components/test/mochitest/test_HSplitBox_01.html b/devtools/client/shared/components/test/mochitest/test_HSplitBox_01.html
new file mode 100644
index 000000000..7a7187de6
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_HSplitBox_01.html
@@ -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/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Basic tests for the HSplitBox component.
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Tree component test</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript "src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+ <link rel="stylesheet" href="resource://devtools/client/themes/splitters.css" type="text/css"/>
+ <link rel="stylesheet" href="chrome://devtools/skin/components-h-split-box.css" type="text/css"/>
+ <style>
+ html {
+ --theme-splitter-color: black;
+ }
+ </style>
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+const FUDGE_FACTOR = .1;
+function aboutEq(a, b) {
+ dumpn(`Checking ${a} ~= ${b}`);
+ return Math.abs(a - b) < FUDGE_FACTOR;
+}
+
+window.onload = Task.async(function* () {
+ try {
+ const React = browserRequire("devtools/client/shared/vendor/react");
+ const ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
+
+ let HSplitBox = React.createFactory(browserRequire("devtools/client/shared/components/h-split-box"));
+ ok(HSplitBox, "Should get HSplitBox");
+
+ const newSizes = [];
+ const box = ReactDOM.render(HSplitBox({
+ start: "hello!",
+ end: "world!",
+ startWidth: .5,
+ onResize(newSize) {
+ newSizes.push(newSize);
+ },
+ }), window.document.body);
+
+ // Test that we properly rendered our two panes.
+
+ let panes = document.querySelectorAll(".h-split-box-pane");
+ is(panes.length, 2, "Should get two panes");
+ is(panes[0].style.flexGrow, "0.5", "Each pane should have .5 width");
+ is(panes[1].style.flexGrow, "0.5", "Each pane should have .5 width");
+ is(panes[0].textContent.trim(), "hello!", "First pane should be hello");
+ is(panes[1].textContent.trim(), "world!", "Second pane should be world");
+
+ // Now change the left width and assert that the changes are reflected.
+
+ yield setProps(box, { startWidth: .25 });
+ panes = document.querySelectorAll(".h-split-box-pane");
+ is(panes.length, 2, "Should still have two panes");
+ is(panes[0].style.flexGrow, "0.25", "First pane's width should be .25");
+ is(panes[1].style.flexGrow, "0.75", "Second pane's width should be .75");
+
+ // Mouse moves without having grabbed the splitter should have no effect.
+
+ let container = document.querySelector(".h-split-box");
+ ok(container, "Should get our container .h-split-box");
+
+ const { left, top, width } = container.getBoundingClientRect();
+ const middle = left + width / 2;
+ const oneQuarter = left + width / 4;
+ const threeQuarters = left + 3 * width / 4;
+
+ synthesizeMouse(container, middle, top, { type: "mousemove" }, window);
+ is(newSizes.length, 0, "Mouse moves without dragging the splitter should have no effect");
+
+ // Send a mouse down on the splitter, and then move the mouse a couple
+ // times. Now we should get resizes.
+
+ const splitter = document.querySelector(".devtools-side-splitter");
+ ok(splitter, "Should get our splitter");
+
+ synthesizeMouseAtCenter(splitter, { button: 0, type: "mousedown" }, window);
+
+ function mouseMove(clientX) {
+ const event = new MouseEvent("mousemove", { clientX });
+ document.defaultView.top.dispatchEvent(event);
+ }
+
+ mouseMove(middle);
+ is(newSizes.length, 1, "Should get 1 resize");
+ ok(aboutEq(newSizes[0], .5), "New size should be ~.5");
+
+ mouseMove(left);
+ is(newSizes.length, 2, "Should get 2 resizes");
+ ok(aboutEq(newSizes[1], 0), "New size should be ~0");
+
+ mouseMove(oneQuarter);
+ is(newSizes.length, 3, "Sould get 3 resizes");
+ ok(aboutEq(newSizes[2], .25), "New size should be ~.25");
+
+ mouseMove(threeQuarters);
+ is(newSizes.length, 4, "Should get 4 resizes");
+ ok(aboutEq(newSizes[3], .75), "New size should be ~.75");
+
+ synthesizeMouseAtCenter(splitter, { button: 0, type: "mouseup" }, window);
+
+ // Now that we have let go of the splitter, mouse moves should not result in resizes.
+
+ synthesizeMouse(container, middle, top, { type: "mousemove" }, window);
+ is(newSizes.length, 4, "Should still have 4 resizes");
+
+ } catch(e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_frame_01.html b/devtools/client/shared/components/test/mochitest/test_frame_01.html
new file mode 100644
index 000000000..ed3bc90c2
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_frame_01.html
@@ -0,0 +1,309 @@
+<!-- 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/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test the formatting of the file name, line and columns are correct in frame components,
+with optional columns, unknown and non-URL sources.
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Frame component test</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+window.onload = Task.async(function* () {
+ try {
+ let ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
+ let React = browserRequire("devtools/client/shared/vendor/react");
+ let Frame = React.createFactory(browserRequire("devtools/client/shared/components/frame"));
+ ok(Frame, "Should get Frame");
+
+ // Check when there's a column
+ yield checkFrameComponent({
+ frame: {
+ source: "http://myfile.com/mahscripts.js",
+ line: 55,
+ column: 10,
+ }
+ }, {
+ file: "mahscripts.js",
+ line: 55,
+ column: 10,
+ shouldLink: true,
+ tooltip: "View source in Debugger → http://myfile.com/mahscripts.js:55:10",
+ });
+
+ // Check when there's no column
+ yield checkFrameComponent({
+ frame: {
+ source: "http://myfile.com/mahscripts.js",
+ line: 55,
+ }
+ }, {
+ file: "mahscripts.js",
+ line: 55,
+ shouldLink: true,
+ tooltip: "View source in Debugger → http://myfile.com/mahscripts.js:55",
+ });
+
+ // Check when column === 0
+ yield checkFrameComponent({
+ frame: {
+ source: "http://myfile.com/mahscripts.js",
+ line: 55,
+ column: 0,
+ }
+ }, {
+ file: "mahscripts.js",
+ line: 55,
+ shouldLink: true,
+ tooltip: "View source in Debugger → http://myfile.com/mahscripts.js:55",
+ });
+
+ // Check when there's no parseable URL source;
+ // should not link but should render line/columns
+ yield checkFrameComponent({
+ frame: {
+ source: "self-hosted",
+ line: 1,
+ }
+ }, {
+ file: "self-hosted",
+ line: "1",
+ shouldLink: false,
+ tooltip: "self-hosted:1",
+ });
+ yield checkFrameComponent({
+ frame: {
+ source: "self-hosted",
+ line: 1,
+ column: 10,
+ }
+ }, {
+ file: "self-hosted",
+ line: "1",
+ column: "10",
+ shouldLink: false,
+ tooltip: "self-hosted:1:10",
+ });
+
+ // Check when there's no source;
+ // should not link but should render line/columns
+ yield checkFrameComponent({
+ frame: {
+ line: 1,
+ }
+ }, {
+ file: "(unknown)",
+ line: "1",
+ shouldLink: false,
+ tooltip: "(unknown):1",
+ });
+ yield checkFrameComponent({
+ frame: {
+ line: 1,
+ column: 10,
+ }
+ }, {
+ file: "(unknown)",
+ line: "1",
+ column: "10",
+ shouldLink: false,
+ tooltip: "(unknown):1:10",
+ });
+
+ // Check when there's a column, but no line;
+ // no line/column info should render
+ yield checkFrameComponent({
+ frame: {
+ source: "http://myfile.com/mahscripts.js",
+ column: 55,
+ }
+ }, {
+ file: "mahscripts.js",
+ shouldLink: true,
+ tooltip: "View source in Debugger → http://myfile.com/mahscripts.js",
+ });
+
+ // Check when line is 0; this should be an invalid
+ // line option, so don't render line/column
+ yield checkFrameComponent({
+ frame: {
+ source: "http://myfile.com/mahscripts.js",
+ line: 0,
+ column: 55,
+ }
+ }, {
+ file: "mahscripts.js",
+ shouldLink: true,
+ tooltip: "View source in Debugger → http://myfile.com/mahscripts.js",
+ });
+
+ // Check when source is via Scratchpad; we should render out the
+ // lines and columns as this is linkable.
+ yield checkFrameComponent({
+ frame: {
+ source: "Scratchpad/1",
+ line: 10,
+ column: 50,
+ }
+ }, {
+ file: "Scratchpad/1",
+ line: 10,
+ column: 50,
+ shouldLink: true,
+ tooltip: "View source in Debugger → Scratchpad/1:10:50",
+ });
+
+ // Check that line and column can be strings
+ yield checkFrameComponent({
+ frame: {
+ source: "http://myfile.com/mahscripts.js",
+ line: "10",
+ column: "55",
+ }
+ }, {
+ file: "mahscripts.js",
+ line: 10,
+ column: 55,
+ shouldLink: true,
+ tooltip: "View source in Debugger → http://myfile.com/mahscripts.js:10:55",
+ });
+
+ // Check that line and column can be strings,
+ // and that the `0` rendering rules apply when they are strings as well
+ yield checkFrameComponent({
+ frame: {
+ source: "http://myfile.com/mahscripts.js",
+ line: "0",
+ column: "55",
+ }
+ }, {
+ file: "mahscripts.js",
+ shouldLink: true,
+ tooltip: "View source in Debugger → http://myfile.com/mahscripts.js",
+ });
+
+ // Check that the showFullSourceUrl option works correctly
+ yield checkFrameComponent({
+ frame: {
+ source: "http://myfile.com/mahscripts.js",
+ line: 0,
+ },
+ showFullSourceUrl: true
+ }, {
+ file: "http://myfile.com/mahscripts.js",
+ shouldLink: true,
+ tooltip: "View source in Debugger → http://myfile.com/mahscripts.js",
+ });
+
+ // Check that the showFunctionName option works correctly
+ yield checkFrameComponent({
+ frame: {
+ functionDisplayName: "myfun",
+ source: "http://myfile.com/mahscripts.js",
+ line: 0,
+ }
+ }, {
+ functionName: null,
+ file: "mahscripts.js",
+ shouldLink: true,
+ tooltip: "View source in Debugger → http://myfile.com/mahscripts.js",
+ });
+
+ yield checkFrameComponent({
+ frame: {
+ functionDisplayName: "myfun",
+ source: "http://myfile.com/mahscripts.js",
+ line: 0,
+ },
+ showFunctionName: true
+ }, {
+ functionName: "myfun",
+ file: "mahscripts.js",
+ shouldLink: true,
+ tooltip: "View source in Debugger → http://myfile.com/mahscripts.js",
+ });
+
+ // Check that anonymous function name is not displayed unless explicitly enabled
+ yield checkFrameComponent({
+ frame: {
+ source: "http://myfile.com/mahscripts.js",
+ line: 0,
+ },
+ showFunctionName: true
+ }, {
+ functionName: null,
+ file: "mahscripts.js",
+ shouldLink: true,
+ tooltip: "View source in Debugger → http://myfile.com/mahscripts.js",
+ });
+
+ yield checkFrameComponent({
+ frame: {
+ source: "http://myfile.com/mahscripts.js",
+ line: 0,
+ },
+ showFunctionName: true,
+ showAnonymousFunctionName: true
+ }, {
+ functionName: "<anonymous>",
+ file: "mahscripts.js",
+ shouldLink: true,
+ tooltip: "View source in Debugger → http://myfile.com/mahscripts.js",
+ });
+
+ // Check if file is rendered with "/" for root documents when showEmptyPathAsHost is false
+ yield checkFrameComponent({
+ frame: {
+ source: "http://www.cnn.com/",
+ line: "1",
+ },
+ showEmptyPathAsHost: false,
+ }, {
+ file: "/",
+ line: "1",
+ shouldLink: true,
+ tooltip: "View source in Debugger → http://www.cnn.com/:1",
+ });
+
+ // Check if file is rendered with hostname for root documents when showEmptyPathAsHost is true
+ yield checkFrameComponent({
+ frame: {
+ source: "http://www.cnn.com/",
+ line: "1",
+ },
+ showEmptyPathAsHost: true,
+ }, {
+ file: "www.cnn.com",
+ line: "1",
+ shouldLink: true,
+ tooltip: "View source in Debugger → http://www.cnn.com/:1",
+ });
+
+ function* checkFrameComponent(input, expected) {
+ let props = Object.assign({ onClick: () => {} }, input);
+ let frame = ReactDOM.render(Frame(props), window.document.body);
+ yield forceRender(frame);
+
+ let el = frame.getDOMNode();
+ let { source } = input.frame;
+ checkFrameString(Object.assign({ el, source }, expected));
+ }
+
+ } catch (e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_notification_box_01.html b/devtools/client/shared/components/test/mochitest/test_notification_box_01.html
new file mode 100644
index 000000000..947fb9803
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_notification_box_01.html
@@ -0,0 +1,108 @@
+<!-- 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/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test for Notification Box. The test is checking:
+* Basic rendering
+* Appending a notification
+* Notification priority
+* Closing notification
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Notification Box</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+window.onload = Task.async(function* () {
+ try {
+ let ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
+ let React = browserRequire("devtools/client/shared/vendor/react");
+ let { NotificationBox, PriorityLevels } = browserRequire("devtools/client/shared/components/notification-box");
+
+ const renderedBox = shallowRenderComponent(NotificationBox, {});
+ is(renderedBox.type, "div", "NotificationBox is rendered as <div>");
+
+ // Test rendering
+ let boxElement = React.createElement(NotificationBox);
+ let notificationBox = TestUtils.renderIntoDocument(boxElement);
+ let notificationNode = ReactDOM.findDOMNode(notificationBox);
+
+ is(notificationNode.className, "notificationbox",
+ "NotificationBox has expected classname");
+ is(notificationNode.textContent, "",
+ "Empty NotificationBox has no text content");
+
+ checkNumberOfNotifications(notificationBox, 0);
+
+ // Append a notification
+ notificationBox.appendNotification(
+ "Info message",
+ "id1",
+ null,
+ PriorityLevels.PRIORITY_INFO_HIGH
+ );
+
+ is (notificationNode.textContent, "Info message",
+ "The box must display notification message");
+ checkNumberOfNotifications(notificationBox, 1);
+
+ // Append more important notification
+ notificationBox.appendNotification(
+ "Critical message",
+ "id2",
+ null,
+ PriorityLevels.PRIORITY_CRITICAL_BLOCK
+ );
+
+ checkNumberOfNotifications(notificationBox, 1);
+
+ is (notificationNode.textContent, "Critical message",
+ "The box must display more important notification message");
+
+ // Append less important notification
+ notificationBox.appendNotification(
+ "Warning message",
+ "id3",
+ null,
+ PriorityLevels.PRIORITY_WARNING_HIGH
+ );
+
+ checkNumberOfNotifications(notificationBox, 1);
+
+ is (notificationNode.textContent, "Critical message",
+ "The box must still display the more important notification");
+
+ ok(notificationBox.getCurrentNotification(),
+ "There must be current notification");
+
+ notificationBox.getNotificationWithValue("id1").close();
+ checkNumberOfNotifications(notificationBox, 1);
+
+ notificationBox.getNotificationWithValue("id2").close();
+ checkNumberOfNotifications(notificationBox, 1);
+
+ notificationBox.getNotificationWithValue("id3").close();
+ checkNumberOfNotifications(notificationBox, 0);
+ } catch(e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+});
+
+function checkNumberOfNotifications(notificationBox, expected) {
+ is(TestUtils.scryRenderedDOMComponentsWithClass(
+ notificationBox, "notification").length, expected,
+ "The notification box must have expected number of notifications");
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_notification_box_02.html b/devtools/client/shared/components/test/mochitest/test_notification_box_02.html
new file mode 100644
index 000000000..ebeb0400d
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_notification_box_02.html
@@ -0,0 +1,70 @@
+<!-- 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/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test for Notification Box. The test is checking:
+* Using custom callback in a notification
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Notification Box</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+window.onload = Task.async(function* () {
+ try {
+ let ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
+ let React = browserRequire("devtools/client/shared/vendor/react");
+ let { NotificationBox, PriorityLevels } = browserRequire("devtools/client/shared/components/notification-box");
+
+ // Test rendering
+ let boxElement = React.createElement(NotificationBox);
+ let notificationBox = TestUtils.renderIntoDocument(boxElement);
+ let notificationNode = ReactDOM.findDOMNode(notificationBox);
+
+ let callbackExecuted = false;
+
+ // Append a notification.
+ notificationBox.appendNotification(
+ "Info message",
+ "id1",
+ null,
+ PriorityLevels.PRIORITY_INFO_LOW,
+ undefined,
+ (reason) => {
+ callbackExecuted = true;
+ is(reason, "removed", "The reason must be expected string");
+ }
+ );
+
+ is(TestUtils.scryRenderedDOMComponentsWithClass(
+ notificationBox, "notification").length, 1,
+ "There must be one notification");
+
+ let closeButton = notificationNode.querySelector(
+ ".messageCloseButton");
+
+ // Click the close button to close the notification.
+ TestUtils.Simulate.click(closeButton);
+
+ is(TestUtils.scryRenderedDOMComponentsWithClass(
+ notificationBox, "notification").length, 0,
+ "The notification box must be empty now");
+
+ ok(callbackExecuted, "Event callback must be executed.");
+ } catch(e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_notification_box_03.html b/devtools/client/shared/components/test/mochitest/test_notification_box_03.html
new file mode 100644
index 000000000..d7fc146fe
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_notification_box_03.html
@@ -0,0 +1,84 @@
+<!-- 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/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test for Notification Box. The test is checking:
+* Using custom buttons in a notification
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Notification Box</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+window.onload = Task.async(function* () {
+ try {
+ let ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
+ let React = browserRequire("devtools/client/shared/vendor/react");
+ let { NotificationBox, PriorityLevels } = browserRequire("devtools/client/shared/components/notification-box");
+
+ // Test rendering
+ let boxElement = React.createElement(NotificationBox);
+ let notificationBox = TestUtils.renderIntoDocument(boxElement);
+ let notificationNode = ReactDOM.findDOMNode(notificationBox);
+
+ let buttonCallbackExecuted = false;
+ var buttons = [{
+ label: "Button1",
+ callback: () => {
+ buttonCallbackExecuted = true;
+
+ // Do not close the notification
+ return true;
+ },
+ }, {
+ label: "Button2",
+ callback: () => {
+ // Close the notification (return value undefined)
+ },
+ }];
+
+ // Append a notification with buttons.
+ notificationBox.appendNotification(
+ "Info message",
+ "id1",
+ null,
+ PriorityLevels.PRIORITY_INFO_LOW,
+ buttons
+ );
+
+ let buttonNodes = notificationNode.querySelectorAll(
+ ".notification-button");
+
+ is(buttonNodes.length, 2, "There must be two buttons");
+
+ // Click the first button
+ TestUtils.Simulate.click(buttonNodes[0]);
+ ok(buttonCallbackExecuted, "Button callback must be executed.");
+
+ is(TestUtils.scryRenderedDOMComponentsWithClass(
+ notificationBox, "notification").length, 1,
+ "There must be one notification");
+
+ // Click the second button (closing the notification)
+ TestUtils.Simulate.click(buttonNodes[1]);
+
+ is(TestUtils.scryRenderedDOMComponentsWithClass(
+ notificationBox, "notification").length, 0,
+ "The notification box must be empty now");
+ } catch(e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_reps_array.html b/devtools/client/shared/components/test/mochitest/test_reps_array.html
new file mode 100644
index 000000000..6ad7f2c43
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_reps_array.html
@@ -0,0 +1,259 @@
+<!-- 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/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test ArrayRep rep
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Rep test - ArrayRep</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+"use strict";
+/* import-globals-from head.js */
+
+window.onload = Task.async(function* () {
+ let { Rep } = browserRequire("devtools/client/shared/components/reps/rep");
+ let { ArrayRep } = browserRequire("devtools/client/shared/components/reps/array");
+
+ let componentUnderTest = ArrayRep;
+ const maxLength = {
+ short: 3,
+ long: 300
+ };
+
+ try {
+ yield testBasic();
+
+ // Test property iterator
+ yield testMaxProps();
+ yield testMoreThanShortMaxProps();
+ yield testMoreThanLongMaxProps();
+ yield testRecursiveArray();
+
+ // Test that properties are rendered as expected by ItemRep
+ yield testNested();
+
+ yield testArray();
+ } catch (e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+
+ function testBasic() {
+ // Test that correct rep is chosen
+ const stub = [];
+ const renderedRep = shallowRenderComponent(Rep, { object: stub });
+ is(renderedRep.type, ArrayRep.rep,
+ `Rep correctly selects ${ArrayRep.rep.displayName}`);
+
+
+ // Test rendering
+ const defaultOutput = `[]`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `[]`,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, "testBasic", componentUnderTest, stub);
+ }
+
+ function testMaxProps() {
+ const stub = [1, "foo", {}];
+ const defaultOutput = `[ 1, "foo", Object ]`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `[3]`,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, "testMaxProps", componentUnderTest, stub);
+ }
+
+ function testMoreThanShortMaxProps() {
+ const stub = Array(maxLength.short + 1).fill("foo");
+ const defaultShortOutput = `[ ${Array(maxLength.short).fill("\"foo\"").join(", ")}, 1 more… ]`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultShortOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `[${maxLength.short + 1}]`,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultShortOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: `[ ${Array(maxLength.short + 1).fill("\"foo\"").join(", ")} ]`,
+ }
+ ];
+
+ testRepRenderModes(modeTests, "testMoreThanMaxProps", componentUnderTest, stub);
+ }
+
+ function testMoreThanLongMaxProps() {
+ const stub = Array(maxLength.long + 1).fill("foo");
+ const defaultShortOutput = `[ ${Array(maxLength.short).fill("\"foo\"").join(", ")}, ${maxLength.long + 1 - maxLength.short} more… ]`;
+ const defaultLongOutput = `[ ${Array(maxLength.long).fill("\"foo\"").join(", ")}, 1 more… ]`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultShortOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `[${maxLength.long + 1}]`,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultShortOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultLongOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, "testMoreThanMaxProps", componentUnderTest, stub);
+ }
+
+ function testRecursiveArray() {
+ let stub = [1];
+ stub.push(stub);
+ const defaultOutput = `[ 1, [2] ]`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `[2]`,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, "testRecursiveArray", componentUnderTest, stub);
+ }
+
+ function testNested() {
+ let stub = [
+ {
+ p1: "s1",
+ p2: ["a1", "a2", "a3"],
+ p3: "s3",
+ p4: "s4"
+ }
+ ];
+ const defaultOutput = `[ Object ]`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `[1]`,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, "testNested", componentUnderTest, stub);
+ }
+
+ function testArray() {
+ let stub = [
+ "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
+ "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"
+ ];
+
+ const defaultOutput = `[ "a", "b", "c", "d", "e", "f", "g", "h", "i", "j",` +
+ ` "k", "l", "m", "n", "o", "p", "q", "r", "s", "t",` +
+ ` "u", "v", "w", "x", "y", "z" ]`;
+ const shortOutput = `[ "a", "b", "c", 23 more… ]`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: shortOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `[26]`,
+ },
+ {
+ mode: "short",
+ expectedOutput: shortOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, "testNested", componentUnderTest, stub);
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_reps_attribute.html b/devtools/client/shared/components/test/mochitest/test_reps_attribute.html
new file mode 100644
index 000000000..aa8a5dfad
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_reps_attribute.html
@@ -0,0 +1,56 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test Attribute rep
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Rep test - Attribute</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+window.onload = Task.async(function* () {
+ try {
+ let { Rep } = browserRequire("devtools/client/shared/components/reps/rep");
+ let { Attribute } = browserRequire("devtools/client/shared/components/reps/attribute");
+
+ let gripStub = {
+ "type": "object",
+ "class": "Attr",
+ "actor": "server1.conn19.obj65",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "DOMNode",
+ "nodeType": 2,
+ "nodeName": "class",
+ "value": "autocomplete-suggestions"
+ }
+ };
+
+ // Test that correct rep is chosen
+ const renderedRep = shallowRenderComponent(Rep, { object: gripStub });
+ is(renderedRep.type, Attribute.rep, `Rep correctly selects ${Attribute.rep.displayName}`);
+
+ // Test rendering
+ const renderedComponent = renderComponent(Attribute.rep, { object: gripStub });
+ is(renderedComponent.textContent, "class=\"autocomplete-suggestions\"", "Attribute rep has expected text content");
+ } catch(e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_reps_comment-node.html b/devtools/client/shared/components/test/mochitest/test_reps_comment-node.html
new file mode 100644
index 000000000..4e03d8b30
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_reps_comment-node.html
@@ -0,0 +1,80 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test comment-node rep
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Rep test - comment-node</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+"use strict";
+
+window.onload = Task.async(function* () {
+ try {
+ let { Rep } = browserRequire("devtools/client/shared/components/reps/rep");
+ let { CommentNode } = browserRequire("devtools/client/shared/components/reps/comment-node");
+
+ let gripStub = {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj47",
+ "class": "Comment",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "DOMNode",
+ "nodeType": 8,
+ "nodeName": "#comment",
+ "textContent": "test\nand test\nand test\nand test\nand test\nand test\nand test"
+ }
+ };
+
+ // Test that correct rep is chosen.
+ const renderedRep = shallowRenderComponent(Rep, { object: gripStub });
+ is(renderedRep.type, CommentNode.rep,
+ `Rep correctly selects ${CommentNode.rep.displayName}`);
+
+ // Test rendering.
+ const renderedComponent = renderComponent(CommentNode.rep, { object: gripStub });
+ is(renderedComponent.className, "objectBox theme-comment",
+ "CommentNode rep has expected class names");
+ is(renderedComponent.textContent,
+ `<!-- test\nand test\nand test\nan…d test\nand test\nand test -->`,
+ "CommentNode rep has expected text content");
+
+ // Test tiny rendering.
+ const tinyRenderedComponent = renderComponent(CommentNode.rep, {
+ object: gripStub,
+ mode: "tiny"
+ });
+ is(tinyRenderedComponent.textContent,
+ `<!-- test\\nand test\\na… test\\nand test -->`,
+ "CommentNode rep has expected text content in tiny mode");
+
+ // Test long rendering.
+ const longRenderedComponent = renderComponent(CommentNode.rep, {
+ object: gripStub,
+ mode: "long"
+ });
+ is(longRenderedComponent.textContent, `<!-- ${gripStub.preview.textContent} -->`,
+ "CommentNode rep has expected text content in long mode");
+ } catch (e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_reps_date-time.html b/devtools/client/shared/components/test/mochitest/test_reps_date-time.html
new file mode 100644
index 000000000..a82783b6b
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_reps_date-time.html
@@ -0,0 +1,79 @@
+<!-- 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/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test DateTime rep
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Rep test - DateTime</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+window.onload = Task.async(function* () {
+ let { Rep } = browserRequire("devtools/client/shared/components/reps/rep");
+ let { DateTime } = browserRequire("devtools/client/shared/components/reps/date-time");
+
+ try {
+ testValid();
+ testInvalid();
+ } catch(e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+
+ function testValid() {
+ let gripStub = {
+ "type": "object",
+ "class": "Date",
+ "actor": "server1.conn0.child1/obj32",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 0,
+ "preview": {
+ "timestamp": 1459372644859
+ }
+ };
+
+ // Test that correct rep is chosen
+ const renderedRep = shallowRenderComponent(Rep, { object: gripStub });
+ is(renderedRep.type, DateTime.rep, `Rep correctly selects ${DateTime.rep.displayName}`);
+
+ // Test rendering
+ const renderedComponent = renderComponent(DateTime.rep, { object: gripStub });
+ is(renderedComponent.textContent, "2016-03-30T21:17:24.859Z", "DateTime rep has expected text content for valid date");
+ }
+
+ function testInvalid() {
+ let gripStub = {
+ "type": "object",
+ "actor": "server1.conn0.child1/obj32",
+ "class": "Date",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 0,
+ "preview": {
+ "timestamp": {
+ "type": "NaN"
+ }
+ }
+ };
+
+ // Test rendering
+ const renderedComponent = renderComponent(DateTime.rep, { object: gripStub });
+ is(renderedComponent.textContent, "Invalid Date", "DateTime rep has expected text content for invalid date");
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_reps_document.html b/devtools/client/shared/components/test/mochitest/test_reps_document.html
new file mode 100644
index 000000000..2afabca44
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_reps_document.html
@@ -0,0 +1,56 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test Document rep
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Rep test - Document</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+window.onload = Task.async(function* () {
+ let { Rep } = browserRequire("devtools/client/shared/components/reps/rep");
+ let { Document } = browserRequire("devtools/client/shared/components/reps/document");
+
+ try {
+ let gripStub = {
+ "type": "object",
+ "class": "HTMLDocument",
+ "actor": "server1.conn17.obj115",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 1,
+ "preview": {
+ "kind": "DOMNode",
+ "nodeType": 9,
+ "nodeName": "#document",
+ "location": "https://www.mozilla.org/en-US/firefox/new/"
+ }
+ };
+
+ // Test that correct rep is chosen
+ const renderedRep = shallowRenderComponent(Rep, { object: gripStub });
+ is(renderedRep.type, Document.rep, `Rep correctly selects ${Document.rep.displayName}`);
+
+ // Test rendering
+ const renderedComponent = renderComponent(Document.rep, { object: gripStub });
+ is(renderedComponent.textContent, "https://www.mozilla.org/en-US/firefox/new/", "Document rep has expected text content");
+ } catch(e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_reps_element-node.html b/devtools/client/shared/components/test/mochitest/test_reps_element-node.html
new file mode 100644
index 000000000..d4e22c7ab
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_reps_element-node.html
@@ -0,0 +1,341 @@
+<!-- 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/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test Element node rep
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Rep test - Element node</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+"use strict";
+
+window.onload = Task.async(function* () {
+ let { Rep } = browserRequire("devtools/client/shared/components/reps/rep");
+ let { ElementNode } = browserRequire("devtools/client/shared/components/reps/element-node");
+
+ try {
+ yield testBodyNode();
+ yield testDocumentElement();
+ yield testNode();
+ yield testNodeWithLeadingAndTrailingSpacesClassName();
+ yield testNodeWithoutAttributes();
+ yield testLotsOfAttributes();
+ yield testSvgNode();
+ yield testSvgNodeInXHTML();
+ } catch (e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+
+ function testBodyNode() {
+ const stub = getGripStub("testBodyNode");
+ const renderedRep = shallowRenderComponent(Rep, { object: stub });
+ is(renderedRep.type, ElementNode.rep,
+ `Rep correctly selects ${ElementNode.rep.displayName} for body node`);
+
+ const renderedComponent = renderComponent(ElementNode.rep, { object: stub });
+ is(renderedComponent.textContent, `<body id="body-id" class="body-class">`,
+ "Element node rep has expected text content for body node");
+
+ const tinyRenderedComponent = renderComponent(
+ ElementNode.rep, { object: stub, mode: "tiny" });
+ is(tinyRenderedComponent.textContent, `body#body-id.body-class`,
+ "Element node rep has expected text content for body node in tiny mode");
+ }
+
+ function testDocumentElement() {
+ const stub = getGripStub("testDocumentElement");
+ const renderedRep = shallowRenderComponent(Rep, { object: stub });
+ is(renderedRep.type, ElementNode.rep,
+ `Rep correctly selects ${ElementNode.rep.displayName} for document element node`);
+
+ const renderedComponent = renderComponent(ElementNode.rep, { object: stub });
+ is(renderedComponent.textContent, `<html dir="ltr" lang="en-US">`,
+ "Element node rep has expected text content for document element node");
+
+ const tinyRenderedComponent = renderComponent(
+ ElementNode.rep, { object: stub, mode: "tiny" });
+ is(tinyRenderedComponent.textContent, `html`,
+ "Element node rep has expected text content for document element in tiny mode");
+ }
+
+ function testNode() {
+ const stub = getGripStub("testNode");
+ const renderedRep = shallowRenderComponent(Rep, { object: stub });
+ is(renderedRep.type, ElementNode.rep,
+ `Rep correctly selects ${ElementNode.rep.displayName} for element node`);
+
+ const renderedComponent = renderComponent(ElementNode.rep, { object: stub });
+ is(renderedComponent.textContent,
+ `<input id="newtab-customize-button" class="bar baz" dir="ltr" ` +
+ `title="Customize your New Tab page" value="foo" type="button">`,
+ "Element node rep has expected text content for element node");
+
+ const tinyRenderedComponent = renderComponent(
+ ElementNode.rep, { object: stub, mode: "tiny" });
+ is(tinyRenderedComponent.textContent,
+ `input#newtab-customize-button.bar.baz`,
+ "Element node rep has expected text content for element node in tiny mode");
+ }
+
+ function testNodeWithLeadingAndTrailingSpacesClassName() {
+ const stub = getGripStub("testNodeWithLeadingAndTrailingSpacesClassName");
+ const renderedRep = shallowRenderComponent(Rep, { object: stub });
+ is(renderedRep.type, ElementNode.rep,
+ `Rep correctly selects ${ElementNode.rep.displayName} for element node`);
+
+ const renderedComponent = renderComponent(ElementNode.rep, { object: stub });
+ is(renderedComponent.textContent,
+ `<body id="nightly-whatsnew" class=" html-ltr ">`,
+ "Element node rep output element node with the class trailing spaces");
+
+ const tinyRenderedComponent = renderComponent(
+ ElementNode.rep, { object: stub, mode: "tiny" });
+ is(tinyRenderedComponent.textContent,
+ `body#nightly-whatsnew.html-ltr`,
+ "Element node rep does not show leading nor trailing spaces " +
+ "on class attribute in tiny mode");
+ }
+
+ function testNodeWithoutAttributes() {
+ const stub = getGripStub("testNodeWithoutAttributes");
+
+ const renderedComponent = renderComponent(ElementNode.rep, { object: stub });
+ is(renderedComponent.textContent, "<p>",
+ "Element node rep has expected text content for element node without attributes");
+
+ const tinyRenderedComponent = renderComponent(
+ ElementNode.rep, { object: stub, mode: "tiny" });
+ is(tinyRenderedComponent.textContent, `p`,
+ "Element node rep has expected text content for element node without attributes");
+ }
+
+ function testLotsOfAttributes() {
+ const stub = getGripStub("testLotsOfAttributes");
+
+ const renderedComponent = renderComponent(ElementNode.rep, { object: stub });
+ is(renderedComponent.textContent,
+ '<p id="lots-of-attributes" a="" b="" c="" d="" e="" f="" g="" ' +
+ 'h="" i="" j="" k="" l="" m="" n="">',
+ "Element node rep has expected text content for node with lots of attributes");
+
+ const tinyRenderedComponent = renderComponent(
+ ElementNode.rep, { object: stub, mode: "tiny" });
+ is(tinyRenderedComponent.textContent, `p#lots-of-attributes`,
+ "Element node rep has expected text content for node in tiny mode");
+ }
+
+ function testSvgNode() {
+ const stub = getGripStub("testSvgNode");
+
+ const renderedRep = shallowRenderComponent(Rep, { object: stub });
+ is(renderedRep.type, ElementNode.rep,
+ `Rep correctly selects ${ElementNode.rep.displayName} for SVG element node`);
+
+ const renderedComponent = renderComponent(ElementNode.rep, { object: stub });
+ is(renderedComponent.textContent,
+ '<clipPath id="clip" class="svg-element">',
+ "Element node rep has expected text content for SVG element node");
+
+ const tinyRenderedComponent = renderComponent(
+ ElementNode.rep, { object: stub, mode: "tiny" });
+ is(tinyRenderedComponent.textContent, `clipPath#clip.svg-element`,
+ "Element node rep has expected text content for SVG element node in tiny mode");
+ }
+
+ function testSvgNodeInXHTML() {
+ const stub = getGripStub("testSvgNodeInXHTML");
+
+ const renderedRep = shallowRenderComponent(Rep, { object: stub });
+ is(renderedRep.type, ElementNode.rep,
+ `Rep correctly selects ${ElementNode.rep.displayName} for XHTML SVG element node`);
+
+ const renderedComponent = renderComponent(ElementNode.rep, { object: stub });
+ is(renderedComponent.textContent,
+ '<svg:circle class="svg-element" cx="0" cy="0" r="5">',
+ "Element node rep has expected text content for XHTML SVG element node");
+
+ const tinyRenderedComponent = renderComponent(
+ ElementNode.rep, { object: stub, mode: "tiny" });
+ is(tinyRenderedComponent.textContent, `svg:circle.svg-element`,
+ "Element node rep has expected text content for XHTML SVG element in tiny mode");
+ }
+
+ function getGripStub(name) {
+ switch (name) {
+ case "testBodyNode":
+ return {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj30",
+ "class": "HTMLBodyElement",
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "DOMNode",
+ "nodeType": 1,
+ "nodeName": "body",
+ "attributes": {
+ "class": "body-class",
+ "id": "body-id"
+ },
+ "attributesLength": 2
+ }
+ };
+ case "testDocumentElement":
+ return {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj40",
+ "class": "HTMLHtmlElement",
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "DOMNode",
+ "nodeType": 1,
+ "nodeName": "html",
+ "attributes": {
+ "dir": "ltr",
+ "lang": "en-US"
+ },
+ "attributesLength": 2
+ }
+ };
+ case "testNode":
+ return {
+ "type": "object",
+ "actor": "server1.conn2.child1/obj116",
+ "class": "HTMLInputElement",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "DOMNode",
+ "nodeType": 1,
+ "nodeName": "input",
+ "attributes": {
+ "id": "newtab-customize-button",
+ "dir": "ltr",
+ "title": "Customize your New Tab page",
+ "class": "bar baz",
+ "value": "foo",
+ "type": "button"
+ },
+ "attributesLength": 6
+ }
+ };
+ case "testNodeWithLeadingAndTrailingSpacesClassName":
+ return {
+ "type": "object",
+ "actor": "server1.conn3.child1/obj59",
+ "class": "HTMLBodyElement",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "DOMNode",
+ "nodeType": 1,
+ "nodeName": "body",
+ "attributes": {
+ "id": "nightly-whatsnew",
+ "class": " html-ltr "
+ },
+ "attributesLength": 2
+ }
+ };
+ case "testNodeWithoutAttributes":
+ return {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj32",
+ "class": "HTMLParagraphElement",
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "DOMNode",
+ "nodeType": 1,
+ "nodeName": "p",
+ "attributes": {},
+ "attributesLength": 1
+ }
+ };
+ case "testLotsOfAttributes":
+ return {
+ "type": "object",
+ "actor": "server1.conn2.child1/obj30",
+ "class": "HTMLParagraphElement",
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "DOMNode",
+ "nodeType": 1,
+ "nodeName": "p",
+ "attributes": {
+ "id": "lots-of-attributes",
+ "a": "",
+ "b": "",
+ "c": "",
+ "d": "",
+ "e": "",
+ "f": "",
+ "g": "",
+ "h": "",
+ "i": "",
+ "j": "",
+ "k": "",
+ "l": "",
+ "m": "",
+ "n": ""
+ },
+ "attributesLength": 15
+ }
+ };
+ case "testSvgNode":
+ return {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj42",
+ "class": "SVGClipPathElement",
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "DOMNode",
+ "nodeType": 1,
+ "nodeName": "clipPath",
+ "attributes": {
+ "id": "clip",
+ "class": "svg-element"
+ },
+ "attributesLength": 0
+ }
+ };
+ case "testSvgNodeInXHTML":
+ return {
+ "type": "object",
+ "actor": "server1.conn3.child1/obj34",
+ "class": "SVGCircleElement",
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "DOMNode",
+ "nodeType": 1,
+ "nodeName": "svg:circle",
+ "attributes": {
+ "class": "svg-element",
+ "cx": "0",
+ "cy": "0",
+ "r": "5"
+ },
+ "attributesLength": 3
+ }
+ };
+ }
+ return null;
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_reps_event.html b/devtools/client/shared/components/test/mochitest/test_reps_event.html
new file mode 100644
index 000000000..7dfe72d6f
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_reps_event.html
@@ -0,0 +1,300 @@
+<!-- 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/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test Event rep
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Rep test - Event</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+window.onload = Task.async(function* () {
+ let { Rep } = browserRequire("devtools/client/shared/components/reps/rep");
+ let { Event } = browserRequire("devtools/client/shared/components/reps/event");
+
+ try {
+ // Test that correct rep is chosen
+ const renderedRep = shallowRenderComponent(Rep, { object: getGripStub("testEvent") });
+ is(renderedRep.type, Event.rep, `Rep correctly selects ${Event.rep.displayName}`);
+
+ yield testEvent();
+ yield testMouseEvent();
+ yield testKeyboardEvent();
+ yield testMessageEvent();
+ } catch(e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+
+ function testEvent() {
+ const renderedComponent = renderComponent(Event.rep, { object: getGripStub("testEvent") });
+ is(renderedComponent.textContent,
+ "Event { isTrusted: true, eventPhase: 2, bubbles: false, 7 more… }",
+ "Event rep has expected text content for an event");
+ }
+
+ function testMouseEvent() {
+ const renderedComponent = renderComponent(Event.rep, { object: getGripStub("testMouseEvent") });
+ is(renderedComponent.textContent,
+ "MouseEvent { clientX: 62, clientY: 18, layerX: 0, 2 more… }",
+ "Event rep has expected text content for a mouse event");
+ }
+
+ function testKeyboardEvent() {
+ const renderedComponent = renderComponent(Event.rep, { object: getGripStub("testKeyboardEvent") });
+ is(renderedComponent.textContent,
+ "KeyboardEvent { key: \"Control\", charCode: 0, keyCode: 17 }",
+ "Event rep has expected text content for a keyboard event");
+ }
+
+ function testMessageEvent() {
+ const renderedComponent = renderComponent(Event.rep, { object: getGripStub("testMessageEvent") });
+ is(renderedComponent.textContent,
+ "MessageEvent { isTrusted: false, data: \"test data\", origin: \"null\", 7 more… }",
+ "Event rep has expected text content for a message event");
+ }
+
+ function getGripStub(name) {
+ switch (name) {
+ case "testEvent":
+ return {
+ "type": "object",
+ "class": "Event",
+ "actor": "server1.conn23.obj35",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 1,
+ "preview": {
+ "kind": "DOMEvent",
+ "type": "beforeprint",
+ "properties": {
+ "isTrusted": true,
+ "currentTarget": {
+ "type": "object",
+ "class": "Window",
+ "actor": "server1.conn23.obj37",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 760,
+ "preview": {
+ "kind": "ObjectWithURL",
+ "url": "http://example.com"
+ }
+ },
+ "eventPhase": 2,
+ "bubbles": false,
+ "cancelable": false,
+ "defaultPrevented": false,
+ "timeStamp": 1466780008434005,
+ "originalTarget": {
+ "type": "object",
+ "class": "Window",
+ "actor": "server1.conn23.obj38",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 760,
+ "preview": {
+ "kind": "ObjectWithURL",
+ "url": "http://example.com"
+ }
+ },
+ "explicitOriginalTarget": {
+ "type": "object",
+ "class": "Window",
+ "actor": "server1.conn23.obj39",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 760,
+ "preview": {
+ "kind": "ObjectWithURL",
+ "url": "http://example.com"
+ }
+ },
+ "NONE": 0
+ },
+ "target": {
+ "type": "object",
+ "class": "Window",
+ "actor": "server1.conn23.obj36",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 760,
+ "preview": {
+ "kind": "ObjectWithURL",
+ "url": "http://example.com"
+ }
+ }
+ }
+ };
+
+ case "testMouseEvent":
+ return {
+ "type": "object",
+ "class": "MouseEvent",
+ "actor": "server1.conn20.obj39",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 1,
+ "preview": {
+ "kind": "DOMEvent",
+ "type": "click",
+ "properties": {
+ "buttons": 0,
+ "clientX": 62,
+ "clientY": 18,
+ "layerX": 0,
+ "layerY": 0
+ },
+ "target": {
+ "type": "object",
+ "class": "HTMLDivElement",
+ "actor": "server1.conn20.obj40",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "DOMNode",
+ "nodeType": 1,
+ "nodeName": "div",
+ "attributes": {
+ "id": "test"
+ },
+ "attributesLength": 1
+ }
+ }
+ }
+ };
+
+ case "testKeyboardEvent":
+ return {
+ "type": "object",
+ "class": "KeyboardEvent",
+ "actor": "server1.conn21.obj49",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 1,
+ "preview": {
+ "kind": "DOMEvent",
+ "type": "keyup",
+ "properties": {
+ "key": "Control",
+ "charCode": 0,
+ "keyCode": 17
+ },
+ "target": {
+ "type": "object",
+ "class": "HTMLBodyElement",
+ "actor": "server1.conn21.obj50",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "DOMNode",
+ "nodeType": 1,
+ "nodeName": "body",
+ "attributes": {},
+ "attributesLength": 0
+ }
+ },
+ "eventKind": "key",
+ "modifiers": []
+ }
+ };
+
+ case "testMessageEvent":
+ return {
+ "type": "object",
+ "class": "MessageEvent",
+ "actor": "server1.conn3.obj34",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 1,
+ "preview": {
+ "kind": "DOMEvent",
+ "type": "message",
+ "properties": {
+ "isTrusted": false,
+ "data": "test data",
+ "origin": "null",
+ "lastEventId": "",
+ "source": {
+ "type": "object",
+ "class": "Window",
+ "actor": "server1.conn3.obj36",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 760,
+ "preview": {
+ "kind": "ObjectWithURL",
+ "url": ""
+ }
+ },
+ "ports": {
+ "type": "object",
+ "class": "Array",
+ "actor": "server1.conn3.obj37",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 0
+ },
+ "currentTarget": {
+ "type": "object",
+ "class": "Window",
+ "actor": "server1.conn3.obj38",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 760,
+ "preview": {
+ "kind": "ObjectWithURL",
+ "url": ""
+ }
+ },
+ "eventPhase": 2,
+ "bubbles": false,
+ "cancelable": false
+ },
+ "target": {
+ "type": "object",
+ "class": "Window",
+ "actor": "server1.conn3.obj35",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 760,
+ "preview": {
+ "kind": "ObjectWithURL",
+ "url": ""
+ }
+ }
+ }
+ };
+
+ }
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_reps_function.html b/devtools/client/shared/components/test/mochitest/test_reps_function.html
new file mode 100644
index 000000000..ede694329
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_reps_function.html
@@ -0,0 +1,206 @@
+<!-- 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/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test Func rep
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Rep test - Func</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+window.onload = Task.async(function* () {
+ let { Rep } = browserRequire("devtools/client/shared/components/reps/rep");
+ let { Func } = browserRequire("devtools/client/shared/components/reps/function");
+
+ const componentUnderTest = Func;
+
+ try {
+ // Test that correct rep is chosen
+ const gripStub = getGripStub("testNamed");
+ const renderedRep = shallowRenderComponent(Rep, { object: gripStub });
+ is(renderedRep.type, Func.rep, `Rep correctly selects ${Func.rep.displayName}`);
+
+ yield testNamed();
+ yield testVarNamed();
+ yield testAnon();
+ yield testLongName();
+ } catch(e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+
+ function testNamed() {
+ // Test declaration: `function testName{ let innerVar = "foo" }`
+ const testName = "testNamed";
+
+ const defaultOutput = `testName()`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
+ }
+
+ function testUserNamed() {
+ // Test declaration: `function testName{ let innerVar = "foo" }`
+ const testName = "testUserNamed";
+
+ const defaultOutput = `testUserName()`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
+ }
+
+ function testVarNamed() {
+ // Test declaration: `let testVarName = function() { }`
+ const testName = "testVarNamed";
+
+ const defaultOutput = `testVarName()`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
+ }
+
+ function testAnon() {
+ // Test declaration: `() => {}`
+ const testName = "testAnon";
+
+ const defaultOutput = `function()`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
+ }
+
+ function testLongName() {
+ // Test declaration: `let f = function loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong() { }`
+ const testName = "testLongName";
+
+ const defaultOutput = `looooooooooooooooooooooooooooooooooooooooooooooooo\u2026ooooooooooooooooooooooooooooooooooooooooooooong()`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
+ }
+
+ function getGripStub(functionName) {
+ switch (functionName) {
+ case "testNamed":
+ return {
+ "type": "object",
+ "class": "Function",
+ "actor": "server1.conn6.obj35",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "name": "testName",
+ "displayName": "testName",
+ "location": {
+ "url": "debugger eval code",
+ "line": 1
+ }
+ };
+
+ case "testUserNamed":
+ return {
+ "type": "object",
+ "class": "Function",
+ "actor": "server1.conn6.obj35",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "name": "testName",
+ "userDisplayName": "testUserName",
+ "displayName": "testName",
+ "location": {
+ "url": "debugger eval code",
+ "line": 1
+ }
+ };
+
+ case "testVarNamed":
+ return {
+ "type": "object",
+ "class": "Function",
+ "actor": "server1.conn7.obj41",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "displayName": "testVarName",
+ "location": {
+ "url": "debugger eval code",
+ "line": 1
+ }
+ };
+
+ case "testAnon":
+ return {
+ "type": "object",
+ "class": "Function",
+ "actor": "server1.conn7.obj45",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "location": {
+ "url": "debugger eval code",
+ "line": 1
+ }
+ };
+
+ case "testLongName":
+ return {
+ "type": "object",
+ "class": "Function",
+ "actor": "server1.conn7.obj67",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "name": "loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong",
+ "displayName": "loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong",
+ "location": {
+ "url": "debugger eval code",
+ "line": 1
+ }
+ };
+ }
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_reps_grip-array.html b/devtools/client/shared/components/test/mochitest/test_reps_grip-array.html
new file mode 100644
index 000000000..db4f0296e
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_reps_grip-array.html
@@ -0,0 +1,707 @@
+<!-- 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/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test GripArray rep
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Rep test - GripArray</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+window.onload = Task.async(function* () {
+ let { Rep } = browserRequire("devtools/client/shared/components/reps/rep");
+ let { GripArray } = browserRequire("devtools/client/shared/components/reps/grip-array");
+
+ let componentUnderTest = GripArray;
+ const maxLength = {
+ short: 3,
+ long: 300
+ };
+
+ try {
+ yield testBasic();
+
+ // Test property iterator
+ yield testMaxProps();
+ yield testMoreThanShortMaxProps();
+ yield testMoreThanLongMaxProps();
+ yield testRecursiveArray();
+ yield testPreviewLimit();
+ yield testNamedNodeMap();
+ yield testNodeList();
+ yield testDocumentFragment();
+ } catch(e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+
+ function testBasic() {
+ // Test array: `[]`
+ const testName = "testBasic";
+
+ // Test that correct rep is chosen
+ const gripStub = getGripStub("testBasic");
+ const renderedRep = shallowRenderComponent(Rep, { object: gripStub });
+ is(renderedRep.type, GripArray.rep, `Rep correctly selects ${GripArray.rep.displayName}`);
+
+ // Test rendering
+ const defaultOutput = `Array []`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `[]`,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
+ }
+
+ function testMaxProps() {
+ // Test array: `[1, "foo", {}]`;
+ const testName = "testMaxProps";
+
+ const defaultOutput = `Array [ 1, "foo", Object ]`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `[3]`,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
+ }
+
+ function testMoreThanShortMaxProps() {
+ // Test array = `["test string"…] //4 items`
+ const testName = "testMoreThanShortMaxProps";
+
+ const defaultOutput = `Array [ ${Array(maxLength.short).fill("\"test string\"").join(", ")}, 1 more… ]`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `[${maxLength.short + 1}]`,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: `Array [ ${Array(maxLength.short + 1).fill("\"test string\"").join(", ")} ]`,
+ }
+ ];
+
+ testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
+ }
+
+ function testMoreThanLongMaxProps() {
+ // Test array = `["test string"…] //301 items`
+ const testName = "testMoreThanLongMaxProps";
+
+ const defaultShortOutput = `Array [ ${Array(maxLength.short).fill("\"test string\"").join(", ")}, ${maxLength.long + 1 - maxLength.short} more… ]`;
+ const defaultLongOutput = `Array [ ${Array(maxLength.long).fill("\"test string\"").join(", ")}, 1 more… ]`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultShortOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `[${maxLength.long + 1}]`,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultShortOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultLongOutput
+ }
+ ];
+
+ testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
+ }
+
+ function testRecursiveArray() {
+ // Test array = `let a = []; a = [a]`
+ const testName = "testRecursiveArray";
+
+ const defaultOutput = `Array [ [1] ]`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `[1]`,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
+ }
+
+ function testPreviewLimit() {
+ const testName = "testPreviewLimit";
+
+ const shortOutput = `Array [ 0, 1, 2, 8 more… ]`;
+ const defaultOutput = `Array [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1 more… ]`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: shortOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `[11]`,
+ },
+ {
+ mode: "short",
+ expectedOutput: shortOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
+ }
+
+ function testNamedNodeMap() {
+ const testName = "testNamedNodeMap";
+
+ const defaultOutput = `NamedNodeMap [ class="myclass", cellpadding="7", border="3" ]`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `[3]`,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
+ }
+
+ function testNodeList() {
+ const testName = "testNodeList";
+ const defaultOutput = "NodeList [ button#btn-1.btn.btn-log, " +
+ "button#btn-2.btn.btn-err, button#btn-3.btn.btn-count ]";
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `[3]`,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
+ }
+
+ function testDocumentFragment() {
+ const testName = "testDocumentFragment";
+
+ const defaultOutput = "DocumentFragment [ li#li-0.list-element, " +
+ "li#li-1.list-element, li#li-2.list-element, 2 more… ]";
+
+ const longOutput = "DocumentFragment [ " +
+ "li#li-0.list-element, li#li-1.list-element, li#li-2.list-element, " +
+ "li#li-3.list-element, li#li-4.list-element ]";
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `[5]`,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: longOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
+ }
+
+ function getGripStub(functionName) {
+ switch (functionName) {
+ case "testBasic":
+ return {
+ "type": "object",
+ "class": "Array",
+ "actor": "server1.conn0.obj35",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 1,
+ "preview": {
+ "kind": "ArrayLike",
+ "length": 0,
+ "items": []
+ }
+ };
+
+ case "testMaxProps":
+ return {
+ "type": "object",
+ "class": "Array",
+ "actor": "server1.conn1.obj35",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 4,
+ "preview": {
+ "kind": "ArrayLike",
+ "length": 3,
+ "items": [
+ 1,
+ "foo",
+ {
+ "type": "object",
+ "class": "Object",
+ "actor": "server1.conn1.obj36",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 0
+ }
+ ]
+ }
+ };
+
+ case "testMoreThanShortMaxProps":
+ let shortArrayGrip = {
+ "type": "object",
+ "class": "Array",
+ "actor": "server1.conn1.obj35",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 4,
+ "preview": {
+ "kind": "ArrayLike",
+ "length": maxLength.short + 1,
+ "items": []
+ }
+ };
+
+ // Generate array grip with length 4, which is more that the maximum
+ // limit in case of the 'short' mode.
+ for (let i = 0; i < maxLength.short + 1; i++) {
+ shortArrayGrip.preview.items.push("test string");
+ }
+
+ return shortArrayGrip;
+
+ case "testMoreThanLongMaxProps":
+ let longArrayGrip = {
+ "type": "object",
+ "class": "Array",
+ "actor": "server1.conn1.obj35",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 4,
+ "preview": {
+ "kind": "ArrayLike",
+ "length": maxLength.long + 1,
+ "items": []
+ }
+ };
+
+ // Generate array grip with length 301, which is more that the maximum
+ // limit in case of the 'long' mode.
+ for (let i = 0; i < maxLength.long + 1; i++) {
+ longArrayGrip.preview.items.push("test string");
+ }
+
+ return longArrayGrip;
+
+ case "testPreviewLimit":
+ return {
+ "type": "object",
+ "class": "Array",
+ "actor": "server1.conn1.obj31",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 12,
+ "preview": {
+ "kind": "ArrayLike",
+ "length": 11,
+ "items": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
+ }
+ };
+
+ case "testRecursiveArray":
+ return {
+ "type": "object",
+ "class": "Array",
+ "actor": "server1.conn3.obj42",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 2,
+ "preview": {
+ "kind": "ArrayLike",
+ "length": 1,
+ "items": [
+ {
+ "type": "object",
+ "class": "Array",
+ "actor": "server1.conn3.obj43",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 2,
+ "preview": {
+ "kind": "ArrayLike",
+ "length": 1
+ }
+ }
+ ]
+ }
+ };
+
+ case "testNamedNodeMap":
+ return {
+ "type": "object",
+ "class": "NamedNodeMap",
+ "actor": "server1.conn3.obj42",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 6,
+ "preview": {
+ "kind": "ArrayLike",
+ "length": 3,
+ "items": [
+ {
+ "type": "object",
+ "class": "Attr",
+ "actor": "server1.conn3.obj43",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "DOMNode",
+ "nodeType": 2,
+ "nodeName": "class",
+ "value": "myclass"
+ }
+ },
+ {
+ "type": "object",
+ "class": "Attr",
+ "actor": "server1.conn3.obj44",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "DOMNode",
+ "nodeType": 2,
+ "nodeName": "cellpadding",
+ "value": "7"
+ }
+ },
+ {
+ "type": "object",
+ "class": "Attr",
+ "actor": "server1.conn3.obj44",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "DOMNode",
+ "nodeType": 2,
+ "nodeName": "border",
+ "value": "3"
+ }
+ }
+ ]
+ }
+ };
+
+ case "testNodeList":
+ return {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj51",
+ "class": "NodeList",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 3,
+ "preview": {
+ "kind": "ArrayLike",
+ "length": 3,
+ "items": [
+ {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj52",
+ "class": "HTMLButtonElement",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "DOMNode",
+ "nodeType": 1,
+ "nodeName": "button",
+ "attributes": {
+ "id": "btn-1",
+ "class": "btn btn-log",
+ "type": "button"
+ },
+ "attributesLength": 3
+ }
+ },
+ {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj53",
+ "class": "HTMLButtonElement",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "DOMNode",
+ "nodeType": 1,
+ "nodeName": "button",
+ "attributes": {
+ "id": "btn-2",
+ "class": "btn btn-err",
+ "type": "button"
+ },
+ "attributesLength": 3
+ }
+ },
+ {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj54",
+ "class": "HTMLButtonElement",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "DOMNode",
+ "nodeType": 1,
+ "nodeName": "button",
+ "attributes": {
+ "id": "btn-3",
+ "class": "btn btn-count",
+ "type": "button"
+ },
+ "attributesLength": 3
+ }
+ }
+ ]
+ }
+ };
+
+ case "testDocumentFragment":
+ return {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj45",
+ "class": "DocumentFragment",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "DOMNode",
+ "nodeType": 11,
+ "nodeName": "#document-fragment",
+ "childNodesLength": 5,
+ "childNodes": [
+ {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj46",
+ "class": "HTMLLIElement",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "DOMNode",
+ "nodeType": 1,
+ "nodeName": "li",
+ "attributes": {
+ "id": "li-0",
+ "class": "list-element"
+ },
+ "attributesLength": 2
+ }
+ },
+ {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj47",
+ "class": "HTMLLIElement",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "DOMNode",
+ "nodeType": 1,
+ "nodeName": "li",
+ "attributes": {
+ "id": "li-1",
+ "class": "list-element"
+ },
+ "attributesLength": 2
+ }
+ },
+ {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj48",
+ "class": "HTMLLIElement",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "DOMNode",
+ "nodeType": 1,
+ "nodeName": "li",
+ "attributes": {
+ "id": "li-2",
+ "class": "list-element"
+ },
+ "attributesLength": 2
+ }
+ },
+ {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj49",
+ "class": "HTMLLIElement",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "DOMNode",
+ "nodeType": 1,
+ "nodeName": "li",
+ "attributes": {
+ "id": "li-3",
+ "class": "list-element"
+ },
+ "attributesLength": 2
+ }
+ },
+ {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj50",
+ "class": "HTMLLIElement",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "DOMNode",
+ "nodeType": 1,
+ "nodeName": "li",
+ "attributes": {
+ "id": "li-4",
+ "class": "list-element"
+ },
+ "attributesLength": 2
+ }
+ }
+ ]
+ }
+ };
+ }
+ return null;
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_reps_grip-map.html b/devtools/client/shared/components/test/mochitest/test_reps_grip-map.html
new file mode 100644
index 000000000..18470367c
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_reps_grip-map.html
@@ -0,0 +1,405 @@
+<!-- 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/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test GripMap rep
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Rep test - GripMap</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+"use strict";
+
+window.onload = Task.async(function* () {
+ let { Rep } = browserRequire("devtools/client/shared/components/reps/rep");
+ let { GripMap } = browserRequire("devtools/client/shared/components/reps/grip-map");
+
+ const componentUnderTest = GripMap;
+
+ try {
+ yield testEmptyMap();
+ yield testSymbolKeyedMap();
+ yield testWeakMap();
+
+ // // Test entries iterator
+ yield testMaxEntries();
+ yield testMoreThanMaxEntries();
+ yield testUninterestingEntries();
+ } catch (e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+
+ function testEmptyMap() {
+ // Test object: `new Map()`
+ const testName = "testEmptyMap";
+
+ // Test that correct rep is chosen
+ const gripStub = getGripStub("testEmptyMap");
+ const renderedRep = shallowRenderComponent(Rep, { object: gripStub });
+ is(renderedRep.type, GripMap.rep, `Rep correctly selects ${GripMap.rep.displayName}`);
+
+ // Test rendering
+ const defaultOutput = `Map { }`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: "Map",
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
+ }
+
+ function testSymbolKeyedMap() {
+ // Test object:
+ // `new Map([[Symbol("a"), "value-a"], [Symbol("b"), "value-b"]])`
+ const testName = "testSymbolKeyedMap";
+
+ const defaultOutput = `Map { Symbol(a): "value-a", Symbol(b): "value-b" }`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: "Map",
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
+ }
+
+ function testWeakMap() {
+ // Test object: `new WeakMap([[{a: "key-a"}, "value-a"]])`
+ const testName = "testWeakMap";
+
+ // Test that correct rep is chosen
+ const gripStub = getGripStub("testWeakMap");
+ const renderedRep = shallowRenderComponent(Rep, { object: gripStub });
+ is(renderedRep.type, GripMap.rep, `Rep correctly selects ${GripMap.rep.displayName}`);
+
+ // Test rendering
+ const defaultOutput = `WeakMap { Object: "value-a" }`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: "WeakMap",
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
+ }
+
+ function testMaxEntries() {
+ // Test object:
+ // `new Map([["key-a","value-a"], ["key-b","value-b"], ["key-c","value-c"]])`
+ const testName = "testMaxEntries";
+
+ const defaultOutput = `Map { key-a: "value-a", key-b: "value-b", key-c: "value-c" }`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: "Map",
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
+ }
+
+ function testMoreThanMaxEntries() {
+ // Test object = `new Map(
+ // [["key-0", "value-0"], ["key-1", "value-1"]], …, ["key-100", "value-100"]]}`
+ const testName = "testMoreThanMaxEntries";
+
+ const defaultOutput =
+ `Map { key-0: "value-0", key-1: "value-1", key-2: "value-2", 98 more… }`;
+
+ // Generate string with 101 entries, which is the max limit for 'long' mode.
+ let longString = Array.from({length: 100}).map((_, i) => `key-${i}: "value-${i}"`);
+ const longOutput = `Map { ${longString.join(", ")}, 1 more… }`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `Map`,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: longOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
+ }
+
+ function testUninterestingEntries() {
+ // Test object:
+ // `new Map([["key-a",null], ["key-b",undefined], ["key-c","value-c"], ["key-d",4]])`
+ const testName = "testUninterestingEntries";
+
+ const defaultOutput =
+ `Map { key-a: null, key-c: "value-c", key-d: 4, 1 more… }`;
+ const longOutput =
+ `Map { key-a: null, key-b: undefined, key-c: "value-c", key-d: 4 }`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `Map`,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: longOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
+ }
+
+ function getGripStub(functionName) {
+ switch (functionName) {
+ case "testEmptyMap":
+ return {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj97",
+ "class": "Map",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "MapLike",
+ "size": 0,
+ "entries": []
+ }
+ };
+
+ case "testSymbolKeyedMap":
+ return {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj118",
+ "class": "Map",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "MapLike",
+ "size": 2,
+ "entries": [
+ [
+ {
+ "type": "symbol",
+ "name": "a"
+ },
+ "value-a"
+ ],
+ [
+ {
+ "type": "symbol",
+ "name": "b"
+ },
+ "value-b"
+ ]
+ ]
+ }
+ };
+
+ case "testWeakMap":
+ return {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj115",
+ "class": "WeakMap",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "MapLike",
+ "size": 1,
+ "entries": [
+ [
+ {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj116",
+ "class": "Object",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 1
+ },
+ "value-a"
+ ]
+ ]
+ }
+ };
+
+ case "testMaxEntries":
+ return {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj109",
+ "class": "Map",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "MapLike",
+ "size": 3,
+ "entries": [
+ [
+ "key-a",
+ "value-a"
+ ],
+ [
+ "key-b",
+ "value-b"
+ ],
+ [
+ "key-c",
+ "value-c"
+ ]
+ ]
+ }
+ };
+
+ case "testMoreThanMaxEntries": {
+ let entryNb = 101;
+ return {
+ "type": "object",
+ "class": "Map",
+ "actor": "server1.conn0.obj332",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "MapLike",
+ "size": entryNb,
+ // Generate 101 entries, which is more that the maximum
+ // limit in case of the 'long' mode.
+ "entries": Array.from({length: entryNb}).map((_, i) => {
+ return [`key-${i}`, `value-${i}`];
+ })
+ }
+ };
+ }
+
+ case "testUninterestingEntries":
+ return {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj111",
+ "class": "Map",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "MapLike",
+ "size": 4,
+ "entries": [
+ [
+ "key-a",
+ {
+ "type": "null"
+ }
+ ],
+ [
+ "key-b",
+ {
+ "type": "undefined"
+ }
+ ],
+ [
+ "key-c",
+ "value-c"
+ ],
+ [
+ "key-d",
+ 4
+ ]
+ ]
+ }
+ };
+ }
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_reps_grip.html b/devtools/client/shared/components/test/mochitest/test_reps_grip.html
new file mode 100644
index 000000000..15d4e1d25
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_reps_grip.html
@@ -0,0 +1,887 @@
+<!-- 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/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test grip rep
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Rep test - grip</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+window.onload = Task.async(function* () {
+ let { Rep } = browserRequire("devtools/client/shared/components/reps/rep");
+ let { Grip } = browserRequire("devtools/client/shared/components/reps/grip");
+
+ const componentUnderTest = Grip;
+
+ try {
+ yield testBasic();
+ yield testBooleanObject();
+ yield testNumberObject();
+ yield testStringObject();
+ yield testProxy();
+ yield testArrayBuffer();
+ yield testSharedArrayBuffer();
+
+ // Test property iterator
+ yield testMaxProps();
+ yield testMoreThanMaxProps();
+ yield testUninterestingProps();
+ yield testNonEnumerableProps();
+
+ // Test that properties are rendered as expected by PropRep
+ yield testNestedObject();
+ yield testNestedArray();
+
+ // Test that 'more' property doesn't clobber the caption.
+ yield testMoreProp();
+ } catch(e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+
+ function testBasic() {
+ // Test object: `{}`
+ const testName = "testBasic";
+
+ // Test that correct rep is chosen
+ const gripStub = getGripStub("testBasic");
+ const renderedRep = shallowRenderComponent(Rep, { object: gripStub });
+ is(renderedRep.type, Grip.rep, `Rep correctly selects ${Grip.rep.displayName}`);
+
+ // Test rendering
+ const defaultOutput = `Object { }`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `Object`,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
+ }
+
+ function testBooleanObject() {
+ // Test object: `new Boolean(true)`
+ const testName = "testBooleanObject";
+
+ // Test that correct rep is chosen
+ const gripStub = getGripStub(testName);
+ const renderedRep = shallowRenderComponent(Rep, { object: gripStub });
+ is(renderedRep.type, Grip.rep, `Rep correctly selects ${Grip.rep.displayName}`);
+
+ // Test rendering
+ const defaultOutput = `Boolean { true }`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `Boolean`,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
+ }
+
+ function testNumberObject() {
+ // Test object: `new Number(42)`
+ const testName = "testNumberObject";
+
+ // Test that correct rep is chosen
+ const gripStub = getGripStub(testName);
+ const renderedRep = shallowRenderComponent(Rep, { object: gripStub });
+ is(renderedRep.type, Grip.rep, `Rep correctly selects ${Grip.rep.displayName}`);
+
+ // Test rendering
+ const defaultOutput = `Number { 42 }`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `Number`,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
+ }
+
+ function testStringObject() {
+ // Test object: `new String("foo")`
+ const testName = "testStringObject";
+
+ // Test that correct rep is chosen
+ const gripStub = getGripStub(testName);
+ const renderedRep = shallowRenderComponent(Rep, { object: gripStub });
+ is(renderedRep.type, Grip.rep, `Rep correctly selects ${Grip.rep.displayName}`);
+
+ // Test rendering
+ const defaultOutput = `String { "foo" }`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `String`,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
+ }
+
+ function testProxy() {
+ // Test object: `new Proxy({a:1},[1,2,3])`
+ const testName = "testProxy";
+
+ // Test that correct rep is chosen
+ const gripStub = getGripStub(testName);
+ const renderedRep = shallowRenderComponent(Rep, { object: gripStub });
+ is(renderedRep.type, Grip.rep, `Rep correctly selects ${Grip.rep.displayName}`);
+
+ // Test rendering
+ const defaultOutput = `Proxy { <target>: Object, <handler>: [3] }`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `Proxy`,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
+ }
+
+ function testArrayBuffer() {
+ // Test object: `new ArrayBuffer(10)`
+ const testName = "testArrayBuffer";
+
+ // Test that correct rep is chosen
+ const gripStub = getGripStub(testName);
+ const renderedRep = shallowRenderComponent(Rep, { object: gripStub });
+ is(renderedRep.type, Grip.rep, `Rep correctly selects ${Grip.rep.displayName}`);
+
+ // Test rendering
+ const defaultOutput = `ArrayBuffer { byteLength: 10 }`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `ArrayBuffer`,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
+ }
+
+ function testSharedArrayBuffer() {
+ // Test object: `new SharedArrayBuffer(5)`
+ const testName = "testSharedArrayBuffer";
+
+ // Test that correct rep is chosen
+ const gripStub = getGripStub(testName);
+ const renderedRep = shallowRenderComponent(Rep, { object: gripStub });
+ is(renderedRep.type, Grip.rep, `Rep correctly selects ${Grip.rep.displayName}`);
+
+ // Test rendering
+ const defaultOutput = `SharedArrayBuffer { byteLength: 5 }`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `SharedArrayBuffer`,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
+ }
+
+ function testMaxProps() {
+ // Test object: `{a: "a", b: "b", c: "c"}`;
+ const testName = "testMaxProps";
+
+ const defaultOutput = `Object { a: "a", b: "b", c: "c" }`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `Object`,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
+ }
+
+ function testMoreThanMaxProps() {
+ // Test object = `{p0: "0", p1: "1", p2: "2", …, p100: "100"}`
+ const testName = "testMoreThanMaxProps";
+
+ const defaultOutput = `Object { p0: "0", p1: "1", p2: "2", 98 more… }`;
+
+ // Generate string with 100 properties, which is the max limit
+ // for 'long' mode.
+ let props = "";
+ for (let i = 0; i < 100; i++) {
+ props += "p" + i + ": \"" + i + "\", ";
+ }
+
+ const longOutput = `Object { ${props}1 more… }`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `Object`,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: longOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
+ }
+
+ function testUninterestingProps() {
+ // Test object: `{a: undefined, b: undefined, c: "c", d: 1}`
+ // @TODO This is not how we actually want the preview to be output.
+ // See https://bugzilla.mozilla.org/show_bug.cgi?id=1276376
+ const expectedOutput = `Object { a: undefined, b: undefined, c: "c", 1 more… }`;
+ }
+
+ function testNonEnumerableProps() {
+ // Test object: `Object.defineProperty({}, "foo", {enumerable : false});`
+ const testName = "testNonEnumerableProps";
+
+ // Test that correct rep is chosen
+ const gripStub = getGripStub("testNonEnumerableProps");
+ const renderedRep = shallowRenderComponent(Rep, { object: gripStub });
+ is(renderedRep.type, Grip.rep, `Rep correctly selects ${Grip.rep.displayName}`);
+
+ // Test rendering
+ const defaultOutput = `Object { }`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `Object`,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
+ }
+
+ function testNestedObject() {
+ // Test object: `{objProp: {id: 1}, strProp: "test string"}`
+ const testName = "testNestedObject";
+
+ const defaultOutput = `Object { objProp: Object, strProp: "test string" }`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `Object`,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
+ }
+
+ function testNestedArray() {
+ // Test object: `{arrProp: ["foo", "bar", "baz"]}`
+ const testName = "testNestedArray";
+
+ const defaultOutput = `Object { arrProp: [3] }`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `Object`,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
+ }
+
+ function testMoreProp() {
+ // Test object: `{a: undefined, b: 1, more: 2, d: 3}`;
+ const testName = "testMoreProp";
+
+ const defaultOutput = `Object { b: 1, more: 2, d: 3, 1 more… }`;
+ const longOutput = `Object { a: undefined, b: 1, more: 2, d: 3 }`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `Object`,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: longOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
+ }
+
+ function getGripStub(functionName) {
+ switch (functionName) {
+ case "testBasic":
+ return {
+ "type": "object",
+ "class": "Object",
+ "actor": "server1.conn0.obj304",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "Object",
+ "ownProperties": {},
+ "ownPropertiesLength": 0,
+ "safeGetterValues": {}
+ }
+ };
+
+ case "testMaxProps":
+ return {
+ "type": "object",
+ "class": "Object",
+ "actor": "server1.conn0.obj337",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 3,
+ "preview": {
+ "kind": "Object",
+ "ownProperties": {
+ "a": {
+ "configurable": true,
+ "enumerable": true,
+ "writable": true,
+ "value": "a"
+ },
+ "b": {
+ "configurable": true,
+ "enumerable": true,
+ "writable": true,
+ "value": "b"
+ },
+ "c": {
+ "configurable": true,
+ "enumerable": true,
+ "writable": true,
+ "value": "c"
+ }
+ },
+ "ownPropertiesLength": 3,
+ "safeGetterValues": {}
+ }
+ };
+
+ case "testMoreThanMaxProps": {
+ let grip = {
+ "type": "object",
+ "class": "Object",
+ "actor": "server1.conn0.obj332",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 101,
+ "preview": {
+ "kind": "Object",
+ "ownProperties": {},
+ "ownPropertiesLength": 101,
+ "safeGetterValues": {}
+ }
+ };
+
+ // Generate 101 properties, which is more that the maximum
+ // limit in case of the 'long' mode.
+ for (let i = 0; i < 101; i++) {
+ grip.preview.ownProperties["p" + i] = {
+ "configurable": true,
+ "enumerable": true,
+ "writable": true,
+ "value": i + ""
+ };
+ }
+
+ return grip;
+ }
+
+ case "testUninterestingProps":
+ return {
+ "type": "object",
+ "class": "Object",
+ "actor": "server1.conn0.obj342",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 4,
+ "preview": {
+ "kind": "Object",
+ "ownProperties": {
+ "a": {
+ "configurable": true,
+ "enumerable": true,
+ "writable": true,
+ "value": {
+ "type": "undefined"
+ }
+ },
+ "b": {
+ "configurable": true,
+ "enumerable": true,
+ "writable": true,
+ "value": {
+ "type": "undefined"
+ }
+ },
+ "c": {
+ "configurable": true,
+ "enumerable": true,
+ "writable": true,
+ "value": "c"
+ },
+ "d": {
+ "configurable": true,
+ "enumerable": true,
+ "writable": true,
+ "value": 1
+ }
+ },
+ "ownPropertiesLength": 4,
+ "safeGetterValues": {}
+ }
+ };
+ case "testNonEnumerableProps":
+ return {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj30",
+ "class": "Object",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 1,
+ "preview": {
+ "kind": "Object",
+ "ownProperties": {},
+ "ownPropertiesLength": 1,
+ "safeGetterValues": {}
+ }
+ };
+ case "testNestedObject":
+ return {
+ "type": "object",
+ "class": "Object",
+ "actor": "server1.conn0.obj145",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 2,
+ "preview": {
+ "kind": "Object",
+ "ownProperties": {
+ "objProp": {
+ "configurable": true,
+ "enumerable": true,
+ "writable": true,
+ "value": {
+ "type": "object",
+ "class": "Object",
+ "actor": "server1.conn0.obj146",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 1
+ }
+ },
+ "strProp": {
+ "configurable": true,
+ "enumerable": true,
+ "writable": true,
+ "value": "test string"
+ }
+ },
+ "ownPropertiesLength": 2,
+ "safeGetterValues": {}
+ }
+ };
+
+ case "testNestedArray":
+ return {
+ "type": "object",
+ "class": "Object",
+ "actor": "server1.conn0.obj326",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 1,
+ "preview": {
+ "kind": "Object",
+ "ownProperties": {
+ "arrProp": {
+ "configurable": true,
+ "enumerable": true,
+ "writable": true,
+ "value": {
+ "type": "object",
+ "class": "Array",
+ "actor": "server1.conn0.obj327",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 4,
+ "preview": {
+ "kind": "ArrayLike",
+ "length": 3
+ }
+ }
+ }
+ },
+ "ownPropertiesLength": 1,
+ "safeGetterValues": {}
+ },
+ };
+
+ case "testMoreProp":
+ return {
+ "type": "object",
+ "class": "Object",
+ "actor": "server1.conn0.obj342",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 4,
+ "preview": {
+ "kind": "Object",
+ "ownProperties": {
+ "a": {
+ "configurable": true,
+ "enumerable": true,
+ "writable": true,
+ "value": {
+ "type": "undefined"
+ }
+ },
+ "b": {
+ "configurable": true,
+ "enumerable": true,
+ "writable": true,
+ "value": 1
+ },
+ "more": {
+ "configurable": true,
+ "enumerable": true,
+ "writable": true,
+ "value": 2
+ },
+ "d": {
+ "configurable": true,
+ "enumerable": true,
+ "writable": true,
+ "value": 3
+ }
+ },
+ "ownPropertiesLength": 4,
+ "safeGetterValues": {}
+ }
+ };
+ case "testBooleanObject":
+ return {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj57",
+ "class": "Boolean",
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "Object",
+ "ownProperties": {},
+ "ownPropertiesLength": 0,
+ "safeGetterValues": {},
+ "wrappedValue": true
+ }
+ };
+ case "testNumberObject":
+ return {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj59",
+ "class": "Number",
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "Object",
+ "ownProperties": {},
+ "ownPropertiesLength": 0,
+ "safeGetterValues": {},
+ "wrappedValue": 42
+ }
+ };
+ case "testStringObject":
+ return {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj61",
+ "class": "String",
+ "ownPropertyLength": 4,
+ "preview": {
+ "kind": "Object",
+ "ownProperties": {},
+ "ownPropertiesLength": 4,
+ "safeGetterValues": {},
+ "wrappedValue": "foo"
+ }
+ };
+ case "testProxy":
+ return {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj47",
+ "class": "Proxy",
+ "proxyTarget": {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj48",
+ "class": "Object",
+ "ownPropertyLength": 1
+ },
+ "proxyHandler": {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj49",
+ "class": "Array",
+ "ownPropertyLength": 4,
+ "preview": {
+ "kind": "ArrayLike",
+ "length": 3
+ }
+ },
+ "preview": {
+ "kind": "Object",
+ "ownProperties": {
+ "<target>": {
+ "value": {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj48",
+ "class": "Object",
+ "ownPropertyLength": 1
+ }
+ },
+ "<handler>": {
+ "value": {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj49",
+ "class": "Array",
+ "ownPropertyLength": 4,
+ "preview": {
+ "kind": "ArrayLike",
+ "length": 3
+ }
+ }
+ }
+ },
+ "ownPropertiesLength": 2
+ }
+ };
+ case "testArrayBuffer":
+ return {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj170",
+ "class": "ArrayBuffer",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "Object",
+ "ownProperties": {},
+ "ownPropertiesLength": 0,
+ "safeGetterValues": {
+ "byteLength": {
+ "getterValue": 10,
+ "getterPrototypeLevel": 1,
+ "enumerable": false,
+ "writable": true
+ }
+ }
+ }
+ };
+ case "testSharedArrayBuffer":
+ return {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj171",
+ "class": "SharedArrayBuffer",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "Object",
+ "ownProperties": {},
+ "ownPropertiesLength": 0,
+ "safeGetterValues": {
+ "byteLength": {
+ "getterValue": 5,
+ "getterPrototypeLevel": 1,
+ "enumerable": false,
+ "writable": true
+ }
+ }
+ }
+ };
+ }
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_reps_infinity.html b/devtools/client/shared/components/test/mochitest/test_reps_infinity.html
new file mode 100644
index 000000000..e3a7e871f
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_reps_infinity.html
@@ -0,0 +1,73 @@
+<!-- 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/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test Infinity rep
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Rep test - Infinity</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+"use strict";
+
+window.onload = Task.async(function* () {
+ let { Rep } = browserRequire("devtools/client/shared/components/reps/rep");
+ let { InfinityRep } = browserRequire("devtools/client/shared/components/reps/infinity");
+
+ try {
+ yield testInfinity();
+ yield testNegativeInfinity();
+ } catch (e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+
+ function testInfinity() {
+ const stub = getGripStub("testInfinity");
+ const renderedRep = shallowRenderComponent(Rep, { object: stub });
+ is(renderedRep.type, InfinityRep.rep,
+ `Rep correctly selects ${InfinityRep.rep.displayName} for Infinity value`);
+
+ const renderedComponent = renderComponent(InfinityRep.rep, { object: stub });
+ is(renderedComponent.textContent, "Infinity",
+ "Infinity rep has expected text content for Infinity");
+ }
+
+ function testNegativeInfinity() {
+ const stub = getGripStub("testNegativeInfinity");
+ const renderedRep = shallowRenderComponent(Rep, { object: stub });
+ is(renderedRep.type, InfinityRep.rep,
+ `Rep correctly selects ${InfinityRep.rep.displayName} for negative Infinity value`);
+
+ const renderedComponent = renderComponent(InfinityRep.rep, { object: stub });
+ is(renderedComponent.textContent, "-Infinity",
+ "Infinity rep has expected text content for negative Infinity");
+ }
+
+ function getGripStub(name) {
+ switch (name) {
+ case "testInfinity":
+ return {
+ type: "Infinity"
+ };
+ case "testNegativeInfinity":
+ return {
+ type: "-Infinity"
+ };
+ }
+ return null;
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_reps_long-string.html b/devtools/client/shared/components/test/mochitest/test_reps_long-string.html
new file mode 100644
index 000000000..3caaac913
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_reps_long-string.html
@@ -0,0 +1,125 @@
+<!-- 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/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test LongString rep
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Rep test - LongString</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+window.onload = Task.async(function* () {
+ let { Rep } = browserRequire("devtools/client/shared/components/reps/rep");
+ let { LongStringRep } = browserRequire("devtools/client/shared/components/reps/long-string");
+
+ try {
+ // Test that correct rep is chosen
+ const renderedRep = shallowRenderComponent(Rep, { object: getGripStub("testMultiline") });
+ is(renderedRep.type, LongStringRep.rep,
+ `Rep correctly selects ${LongStringRep.rep.displayName}`);
+
+ // Test rendering
+ yield testMultiline();
+ yield testMultilineOpen();
+ yield testFullText();
+ yield testMultilineLimit();
+ yield testUseQuotes();
+ } catch (e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+
+ function testMultiline() {
+ const stub = getGripStub("testMultiline");
+ const renderedComponent = renderComponent(
+ LongStringRep.rep, { object: stub });
+
+ is(renderedComponent.textContent, `"${stub.initial}…"`,
+ "LongString rep has expected text content for multiline string");
+ }
+
+ function testMultilineLimit() {
+ const renderedComponent = renderComponent(
+ LongStringRep.rep, { object: getGripStub("testMultiline"), cropLimit: 20 });
+
+ is(
+ renderedComponent.textContent,
+ `"a\naaaaaaaaaaaaaaaaaa…"`,
+ "LongString rep has expected text content for multiline string " +
+ "with specified number of characters");
+ }
+
+ function testMultilineOpen() {
+ const stub = getGripStub("testMultiline");
+ const renderedComponent = renderComponent(
+ LongStringRep.rep, { object: stub, member: {open: true}, cropLimit: 20 });
+
+ is(renderedComponent.textContent, `"${stub.initial}…"`,
+ "LongString rep has expected text content for multiline string when open");
+ }
+
+ function testFullText() {
+ const stub = getGripStub("testFullText");
+ const renderedComponentOpen = renderComponent(
+ LongStringRep.rep, { object: stub, member: {open: true}, cropLimit: 20 });
+
+ is(renderedComponentOpen.textContent, `"${stub.fullText}"`,
+ "LongString rep has expected text content when grip has a fullText " +
+ "property and is open");
+
+ const renderedComponentNotOpen = renderComponent(
+ LongStringRep.rep, { object: stub, cropLimit: 20 });
+
+ is(renderedComponentNotOpen.textContent,
+ `"a\naaaaaaaaaaaaaaaaaa…"`,
+ "LongString rep has expected text content when grip has a fullText " +
+ "property and is not open");
+ }
+
+ function testUseQuotes() {
+ const renderedComponent = renderComponent(LongStringRep.rep,
+ { object: getGripStub("testMultiline"), cropLimit: 20, useQuotes: false });
+
+ is(renderedComponent.textContent,
+ "a\naaaaaaaaaaaaaaaaaa…",
+ "LongString rep was expected to omit quotes");
+ }
+
+ function getGripStub(name) {
+ const multilineFullText = "a\n" + Array(20000).fill("a").join("");
+ const fullTextLength = multilineFullText.length;
+ const initialText = multilineFullText.substring(0, 10000);
+
+ switch (name) {
+ case "testMultiline":
+ return {
+ "type": "longString",
+ "initial": initialText,
+ "length": fullTextLength,
+ "actor": "server1.conn1.child1/longString58"
+ };
+ case "testFullText":
+ return {
+ "type": "longString",
+ "fullText": multilineFullText,
+ "initial": initialText,
+ "length": fullTextLength,
+ "actor": "server1.conn1.child1/longString58"
+ };
+ }
+ return null;
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_reps_nan.html b/devtools/client/shared/components/test/mochitest/test_reps_nan.html
new file mode 100644
index 000000000..35dc5a08f
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_reps_nan.html
@@ -0,0 +1,48 @@
+<!-- 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/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test NaN rep
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Rep test - NaN</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+"use strict";
+
+window.onload = Task.async(function* () {
+ let { Rep } = browserRequire("devtools/client/shared/components/reps/rep");
+ let { NaNRep } = browserRequire("devtools/client/shared/components/reps/nan");
+
+ try {
+ yield testNaN();
+ } catch (e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+
+ function testNaN() {
+ const stub = {
+ type: "NaN"
+ };
+ const renderedRep = shallowRenderComponent(Rep, {object: stub});
+ is(renderedRep.type, NaNRep.rep,
+ `Rep correctly selects ${NaNRep.rep.displayName} for NaN value`);
+
+ const renderedComponent = renderComponent(NaNRep.rep, {object: stub});
+ is(renderedComponent.textContent, "NaN", "NaN rep has expected text content");
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_reps_null.html b/devtools/client/shared/components/test/mochitest/test_reps_null.html
new file mode 100644
index 000000000..99a06fed1
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_reps_null.html
@@ -0,0 +1,44 @@
+<!-- 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/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test Null rep
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Rep test - Null</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+window.onload = Task.async(function* () {
+ try {
+ let { Rep } = browserRequire("devtools/client/shared/components/reps/rep");
+ let { Null } = browserRequire("devtools/client/shared/components/reps/null");
+
+ let gripStub = {
+ "type": "null"
+ };
+
+ // Test that correct rep is chosen
+ const renderedRep = shallowRenderComponent(Rep, { object: gripStub });
+ is(renderedRep.type, Null.rep, `Rep correctly selects ${Null.rep.displayName}`);
+
+ // Test rendering
+ const renderedComponent = renderComponent(Null.rep, { object: gripStub });
+ is(renderedComponent.textContent, "null", "Null rep has expected text content");
+ } catch(e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_reps_number.html b/devtools/client/shared/components/test/mochitest/test_reps_number.html
new file mode 100644
index 000000000..50f91d8b0
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_reps_number.html
@@ -0,0 +1,97 @@
+<!-- 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/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test Number rep
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Rep test - Number</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+window.onload = Task.async(function* () {
+ let { Rep } = browserRequire("devtools/client/shared/components/reps/rep");
+ let { Number } = browserRequire("devtools/client/shared/components/reps/number");
+
+ try {
+ yield testInt();
+ yield testBoolean();
+ yield testNegativeZero();
+ yield testUnsafeInt();
+ } catch(e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+
+
+ function testInt() {
+ const renderedRep = shallowRenderComponent(Rep, { object: getGripStub("testInt") });
+ is(renderedRep.type, Number.rep, `Rep correctly selects ${Number.rep.displayName} for integer value`);
+
+ const renderedComponent = renderComponent(Number.rep, { object: getGripStub("testInt") });
+ is(renderedComponent.textContent, "5", "Number rep has expected text content for integer");
+ }
+
+ function testBoolean() {
+ const renderedRep = shallowRenderComponent(Rep, { object: getGripStub("testTrue") });
+ is(renderedRep.type, Number.rep, `Rep correctly selects ${Number.rep.displayName} for boolean value`);
+
+ let renderedComponent = renderComponent(Number.rep, { object: getGripStub("testTrue") });
+ is(renderedComponent.textContent, "true", "Number rep has expected text content for boolean true");
+
+ renderedComponent = renderComponent(Number.rep, { object: getGripStub("testFalse") });
+ is(renderedComponent.textContent, "false", "Number rep has expected text content for boolean false");
+ }
+
+ function testNegativeZero() {
+ const renderedRep = shallowRenderComponent(Rep, { object: getGripStub("testNegZeroGrip") });
+ is(renderedRep.type, Number.rep, `Rep correctly selects ${Number.rep.displayName} for negative zero value`);
+
+ let renderedComponent = renderComponent(Number.rep, { object: getGripStub("testNegZeroGrip") });
+ is(renderedComponent.textContent, "-0", "Number rep has expected text content for negative zero grip");
+
+ renderedComponent = renderComponent(Number.rep, { object: getGripStub("testNegZeroValue") });
+ is(renderedComponent.textContent, "-0", "Number rep has expected text content for negative zero value");
+ }
+
+ function testUnsafeInt() {
+ const renderedComponent = renderComponent(Number.rep, { object: getGripStub("testUnsafeInt") });
+ is(renderedComponent.textContent, "900719925474099100", "Number rep has expected text content for a long number");
+ }
+
+ function getGripStub(name) {
+ switch (name) {
+ case "testInt":
+ return 5;
+
+ case "testTrue":
+ return true;
+
+ case "testFalse":
+ return false;
+
+ case "testNegZeroValue":
+ return -0;
+
+ case "testNegZeroGrip":
+ return {
+ "type": "-0"
+ };
+
+ case "testUnsafeInt":
+ return 900719925474099122;
+ }
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_reps_object-with-text.html b/devtools/client/shared/components/test/mochitest/test_reps_object-with-text.html
new file mode 100644
index 000000000..eeb4aa325
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_reps_object-with-text.html
@@ -0,0 +1,54 @@
+<!-- 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/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test ObjectWithText rep
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Rep test - ObjectWithText</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+window.onload = Task.async(function* () {
+ try {
+ let { Rep } = browserRequire("devtools/client/shared/components/reps/rep");
+ let { ObjectWithText } = browserRequire("devtools/client/shared/components/reps/object-with-text");
+
+ let gripStub = {
+ "type": "object",
+ "class": "CSSStyleRule",
+ "actor": "server1.conn3.obj273",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "ObjectWithText",
+ "text": ".Shadow"
+ }
+ };
+
+ // Test that correct rep is chosen
+ const renderedRep = shallowRenderComponent(Rep, { object: gripStub });
+ is(renderedRep.type, ObjectWithText.rep, `Rep correctly selects ${ObjectWithText.rep.displayName}`);
+
+ // Test rendering
+ const renderedComponent = renderComponent(ObjectWithText.rep, { object: gripStub });
+ is(renderedComponent.textContent, "\".Shadow\"", "ObjectWithText rep has expected text content");
+ } catch(e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_reps_object-with-url.html b/devtools/client/shared/components/test/mochitest/test_reps_object-with-url.html
new file mode 100644
index 000000000..488c28dc2
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_reps_object-with-url.html
@@ -0,0 +1,60 @@
+<!-- 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/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test ObjectWithURL rep
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Rep test - ObjectWithURL</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+window.onload = Task.async(function* () {
+ try {
+ let ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
+ let React = browserRequire("devtools/client/shared/vendor/react");
+ let { Rep } = browserRequire("devtools/client/shared/components/reps/rep");
+ let { ObjectWithURL } = browserRequire("devtools/client/shared/components/reps/object-with-url");
+
+ let gripStub = {
+ "type": "object",
+ "class": "Location",
+ "actor": "server1.conn2.obj272",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 15,
+ "preview": {
+ "kind": "ObjectWithURL",
+ "url": "https://www.mozilla.org/en-US/"
+ }
+ };
+
+ // Test that correct rep is chosen
+ const renderedRep = shallowRenderComponent(Rep, { object: gripStub });
+ is(renderedRep.type, ObjectWithURL.rep, `Rep correctly selects ${ObjectWithURL.rep.displayName}`);
+
+ // Test rendering
+ const renderedComponent = renderComponent(ObjectWithURL.rep, { object: gripStub });
+ ok(renderedComponent.className.includes("objectBox-Location"), "ObjectWithURL rep has expected class name");
+ const innerNode = renderedComponent.querySelector(".objectPropValue");
+ is(innerNode.textContent, "https://www.mozilla.org/en-US/", "ObjectWithURL rep has expected inner HTML structure and text content");
+
+ // @TODO test link once Bug 1245303 has been implemented.
+ } catch(e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_reps_object.html b/devtools/client/shared/components/test/mochitest/test_reps_object.html
new file mode 100644
index 000000000..c3332361d
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_reps_object.html
@@ -0,0 +1,225 @@
+<!-- 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/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test Obj rep
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Rep test - Obj</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+window.onload = Task.async(function* () {
+ let { Rep } = browserRequire("devtools/client/shared/components/reps/rep");
+ let { Obj } = browserRequire("devtools/client/shared/components/reps/object");
+
+ const componentUnderTest = Obj;
+
+ try {
+ yield testBasic();
+
+ // Test property iterator
+ yield testMaxProps();
+ yield testMoreThanMaxProps();
+ yield testUninterestingProps();
+
+ // Test that properties are rendered as expected by PropRep
+ yield testNested();
+
+ // Test that 'more' property doesn't clobber the caption.
+ yield testMoreProp();
+ } catch(e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+
+ function testBasic() {
+ const stub = {};
+
+ // Test that correct rep is chosen
+ const renderedRep = shallowRenderComponent(Rep, { object: stub });
+ is(renderedRep.type, Obj.rep, `Rep correctly selects ${Obj.rep.displayName}`);
+
+ // Test rendering
+ const defaultOutput = `Object`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, "testBasic", componentUnderTest, stub);
+ }
+
+ function testMaxProps() {
+ const testName = "testMaxProps";
+
+ const stub = {a: "a", b: "b", c: "c"};
+ const defaultOutput = `Object { a: "a", b: "b", c: "c" }`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `Object`,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, "testMaxProps", componentUnderTest, stub);
+ }
+
+ function testMoreThanMaxProps() {
+ let stub = {};
+ for (let i = 0; i<100; i++) {
+ stub[`p${i}`] = i
+ }
+ const defaultOutput = `Object { p0: 0, p1: 1, p2: 2, 97 more… }`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `Object`,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, "testMoreThanMaxProps", componentUnderTest, stub);
+ }
+
+ function testUninterestingProps() {
+ const stub = {a:undefined, b:undefined, c:"c", d:0};
+ const defaultOutput = `Object { c: "c", d: 0, a: undefined, 1 more… }`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `Object`,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, "testUninterestingProps", componentUnderTest, stub);
+ }
+
+ function testNested() {
+ const stub = {
+ objProp: {
+ id: 1,
+ arr: [2]
+ },
+ strProp: "test string",
+ arrProp: [1]
+ };
+ const defaultOutput = `Object { strProp: "test string", objProp: Object, arrProp: [1] }`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `Object`,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, "testNestedObject", componentUnderTest, stub);
+ }
+
+ function testMoreProp() {
+ const stub = {
+ a: undefined,
+ b: 1,
+ 'more': 2,
+ d: 3
+ };
+ const defaultOutput = `Object { b: 1, more: 2, d: 3, 1 more… }`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `Object`,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, "testMoreProp", componentUnderTest, stub);
+ }});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_reps_promise.html b/devtools/client/shared/components/test/mochitest/test_reps_promise.html
new file mode 100644
index 000000000..31de7136d
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_reps_promise.html
@@ -0,0 +1,333 @@
+<!-- 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/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test Promise rep
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Rep test - Promise</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+"use strict";
+
+window.onload = Task.async(function* () {
+ let { Rep } = browserRequire("devtools/client/shared/components/reps/rep");
+ let { PromiseRep } = browserRequire("devtools/client/shared/components/reps/promise");
+
+ const componentUnderTest = PromiseRep;
+
+ try {
+ yield testPending();
+ yield testFulfilledWithNumber();
+ yield testFulfilledWithString();
+ yield testFulfilledWithObject();
+ yield testFulfilledWithArray();
+ } catch (e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+
+ function testPending() {
+ // Test object = `new Promise((resolve, reject) => true)`
+ const stub = getGripStub("testPending");
+
+ // Test that correct rep is chosen.
+ const renderedRep = shallowRenderComponent(Rep, { object: stub });
+ is(renderedRep.type, PromiseRep.rep,
+ `Rep correctly selects ${PromiseRep.rep.displayName} for pending Promise`);
+
+ // Test rendering
+ const defaultOutput = `Promise { <state>: "pending" }`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `Promise { "pending" }`,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, "testPending", componentUnderTest, stub);
+ }
+ function testFulfilledWithNumber() {
+ // Test object = `Promise.resolve(42)`
+ const stub = getGripStub("testFulfilledWithNumber");
+
+ // Test that correct rep is chosen.
+ const renderedRep = shallowRenderComponent(Rep, { object: stub });
+ const {displayName} = PromiseRep.rep;
+ is(renderedRep.type, PromiseRep.rep,
+ `Rep correctly selects ${displayName} for Promise fulfilled with a number`);
+
+ // Test rendering
+ const defaultOutput = `Promise { <state>: "fulfilled", <value>: 42 }`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `Promise { "fulfilled" }`,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, "testFulfilledWithNumber", componentUnderTest, stub);
+ }
+ function testFulfilledWithString() {
+ // Test object = `Promise.resolve("foo")`
+ const stub = getGripStub("testFulfilledWithString");
+
+ // Test that correct rep is chosen.
+ const renderedRep = shallowRenderComponent(Rep, { object: stub });
+ const {displayName} = PromiseRep.rep;
+ is(renderedRep.type, PromiseRep.rep,
+ `Rep correctly selects ${displayName} for Promise fulfilled with a string`);
+
+ // Test rendering
+ const defaultOutput = `Promise { <state>: "fulfilled", <value>: "foo" }`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `Promise { "fulfilled" }`,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, "testFulfilledWithString", componentUnderTest, stub);
+ }
+
+ function testFulfilledWithObject() {
+ // Test object = `Promise.resolve({foo: "bar", baz: "boo"})`
+ const stub = getGripStub("testFulfilledWithObject");
+
+ // Test that correct rep is chosen.
+ const renderedRep = shallowRenderComponent(Rep, { object: stub });
+ const {displayName} = PromiseRep.rep;
+ is(renderedRep.type, PromiseRep.rep,
+ `Rep correctly selects ${displayName} for Promise fulfilled with an object`);
+
+ // Test rendering
+ const defaultOutput = `Promise { <state>: "fulfilled", <value>: Object }`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `Promise { "fulfilled" }`,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, "testFulfilledWithObject", componentUnderTest, stub);
+ }
+
+ function testFulfilledWithArray() {
+ // Test object = `Promise.resolve([1,2,3])`
+ const stub = getGripStub("testFulfilledWithArray");
+
+ // Test that correct rep is chosen.
+ const renderedRep = shallowRenderComponent(Rep, { object: stub });
+ const {displayName} = PromiseRep.rep;
+ is(renderedRep.type, PromiseRep.rep,
+ `Rep correctly selects ${displayName} for Promise fulfilled with an array`);
+
+ // Test rendering
+ const defaultOutput = `Promise { <state>: "fulfilled", <value>: [3] }`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: `Promise { "fulfilled" }`,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, "testFulfilledWithArray", componentUnderTest, stub);
+ }
+
+ function getGripStub(name) {
+ switch (name) {
+ case "testPending":
+ return {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj54",
+ "class": "Promise",
+ "promiseState": {
+ "state": "pending",
+ "creationTimestamp": 1477327760242.5752
+ },
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "Object",
+ "ownProperties": {},
+ "ownPropertiesLength": 0,
+ "safeGetterValues": {}
+ }
+ };
+ case "testFulfilledWithNumber":
+ return {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj55",
+ "class": "Promise",
+ "promiseState": {
+ "state": "fulfilled",
+ "value": 42,
+ "creationTimestamp": 1477327760242.721,
+ "timeToSettle": 0.018497000000479602
+ },
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "Object",
+ "ownProperties": {},
+ "ownPropertiesLength": 0,
+ "safeGetterValues": {}
+ }
+ };
+ case "testFulfilledWithString":
+ return {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj56",
+ "class": "Promise",
+ "promiseState": {
+ "state": "fulfilled",
+ "value": "foo",
+ "creationTimestamp": 1477327760243.2483,
+ "timeToSettle": 0.0019969999998465937
+ },
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "Object",
+ "ownProperties": {},
+ "ownPropertiesLength": 0,
+ "safeGetterValues": {}
+ }
+ };
+ case "testFulfilledWithObject":
+ return {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj59",
+ "class": "Promise",
+ "promiseState": {
+ "state": "fulfilled",
+ "value": {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj60",
+ "class": "Object",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 2
+ },
+ "creationTimestamp": 1477327760243.2214,
+ "timeToSettle": 0.002035999999861815
+ },
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "Object",
+ "ownProperties": {},
+ "ownPropertiesLength": 0,
+ "safeGetterValues": {}
+ }
+ };
+ case "testFulfilledWithArray":
+ return {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj57",
+ "class": "Promise",
+ "promiseState": {
+ "state": "fulfilled",
+ "value": {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj58",
+ "class": "Array",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 4,
+ "preview": {
+ "kind": "ArrayLike",
+ "length": 3
+ }
+ },
+ "creationTimestamp": 1477327760242.9597,
+ "timeToSettle": 0.006158000000141328
+ },
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "Object",
+ "ownProperties": {},
+ "ownPropertiesLength": 0,
+ "safeGetterValues": {}
+ }
+ };
+ }
+ return null;
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_reps_regexp.html b/devtools/client/shared/components/test/mochitest/test_reps_regexp.html
new file mode 100644
index 000000000..074948494
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_reps_regexp.html
@@ -0,0 +1,51 @@
+<!-- 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/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test RegExp rep
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Rep test - RegExp</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+window.onload = Task.async(function* () {
+ try {
+ let { Rep } = browserRequire("devtools/client/shared/components/reps/rep");
+ let { RegExp } = browserRequire("devtools/client/shared/components/reps/regexp");
+
+ let gripStub = {
+ "type": "object",
+ "class": "RegExp",
+ "actor": "server1.conn22.obj39",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 1,
+ "displayString": "/ab+c/i"
+ };
+
+ // Test that correct rep is chosen
+ const renderedRep = shallowRenderComponent(Rep, { object: gripStub });
+ is(renderedRep.type, RegExp.rep, `Rep correctly selects ${RegExp.rep.displayName}`);
+
+ // Test rendering
+ const renderedComponent = renderComponent(RegExp.rep, { object: gripStub });
+ is(renderedComponent.textContent, "/ab+c/i", "RegExp rep has expected text content");
+ } catch(e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_reps_string.html b/devtools/client/shared/components/test/mochitest/test_reps_string.html
new file mode 100644
index 000000000..f9fc9e5b0
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_reps_string.html
@@ -0,0 +1,79 @@
+<!-- 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/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test String rep
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Rep test - String</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+window.onload = Task.async(function* () {
+ let { Rep } = browserRequire("devtools/client/shared/components/reps/rep");
+ let { StringRep } = browserRequire("devtools/client/shared/components/reps/string");
+
+ try {
+ // Test that correct rep is chosen
+ const renderedRep = shallowRenderComponent(Rep, { object: getGripStub("testMultiline") });
+ is(renderedRep.type, StringRep.rep, `Rep correctly selects ${StringRep.rep.displayName}`);
+
+ // Test rendering
+ yield testMultiline();
+ yield testMultilineOpen();
+ yield testMultilineLimit();
+ yield testUseQuotes();
+ yield testNonPritableCharacters();
+ } catch(e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+
+ function testMultiline() {
+ const renderedComponent = renderComponent(StringRep.rep, { object: getGripStub("testMultiline") });
+ is(renderedComponent.textContent, "\"aaaaaaaaaaaaaaaaaaaaa\nbbbbbbbbbbbbbbbbbbb\ncccccccccccccccc\n\"", "String rep has expected text content for multiline string");
+ }
+
+ function testMultilineLimit() {
+ const renderedComponent = renderComponent(StringRep.rep, { object: getGripStub("testMultiline"), cropLimit: 20 });
+ is(renderedComponent.textContent, "\"aaaaaaaaaa…cccccccc\n\"", "String rep has expected text content for multiline string with specified number of characters");
+ }
+
+ function testMultilineOpen() {
+ const renderedComponent = renderComponent(StringRep.rep, { object: getGripStub("testMultiline"), member: {open: true} });
+ is(renderedComponent.textContent, "\"aaaaaaaaaaaaaaaaaaaaa\nbbbbbbbbbbbbbbbbbbb\ncccccccccccccccc\n\"", "String rep has expected text content for multiline string when open");
+ }
+
+ function testUseQuotes(){
+ const renderedComponent = renderComponent(StringRep.rep, { object: getGripStub("testUseQuotes"), useQuotes: false });
+ is(renderedComponent.textContent, "abc", "String rep was expected to omit quotes");
+ }
+
+ function testNonPritableCharacters(){
+ const renderedComponent = renderComponent(StringRep.rep, { object: getGripStub("testNonPritableCharacters"), useQuotes: false });
+ is(renderedComponent.textContent, "a\ufffdb", "String rep was expected to omit non printable characters");
+ }
+
+ function getGripStub(name) {
+ switch (name) {
+ case "testMultiline":
+ return "aaaaaaaaaaaaaaaaaaaaa\nbbbbbbbbbbbbbbbbbbb\ncccccccccccccccc\n";
+ case "testUseQuotes":
+ return "abc";
+ case "testNonPritableCharacters":
+ return "a\x01b";
+ }
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_reps_stylesheet.html b/devtools/client/shared/components/test/mochitest/test_reps_stylesheet.html
new file mode 100644
index 000000000..6f54dee48
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_reps_stylesheet.html
@@ -0,0 +1,54 @@
+<!-- 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/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test Stylesheet rep
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Rep test - Stylesheet</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+window.onload = Task.async(function* () {
+ try {
+ let { Rep } = browserRequire("devtools/client/shared/components/reps/rep");
+ let { StyleSheet } = browserRequire("devtools/client/shared/components/reps/stylesheet");
+
+ let gripStub = {
+ "type": "object",
+ "class": "CSSStyleSheet",
+ "actor": "server1.conn2.obj1067",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 0,
+ "preview": {
+ "kind": "ObjectWithURL",
+ "url": "https://example.com/styles.css"
+ }
+ };
+
+ // Test that correct rep is chosen
+ const renderedRep = shallowRenderComponent(Rep, { object: gripStub });
+ is(renderedRep.type, StyleSheet.rep, `Rep correctly selects ${StyleSheet.rep.displayName}`);
+
+ // Test rendering
+ const renderedComponent = renderComponent(StyleSheet.rep, { object: gripStub });
+ is(renderedComponent.textContent, "StyleSheet https://example.com/styles.css", "StyleSheet rep has expected text content");
+ } catch(e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_reps_symbol.html b/devtools/client/shared/components/test/mochitest/test_reps_symbol.html
new file mode 100644
index 000000000..0112eac0f
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_reps_symbol.html
@@ -0,0 +1,77 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test Symbol rep
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Rep test - String</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+"use strict";
+/* import-globals-from head.js */
+
+window.onload = Task.async(function* () {
+ let { Rep } = browserRequire("devtools/client/shared/components/reps/rep");
+ let { SymbolRep } = browserRequire("devtools/client/shared/components/reps/symbol");
+
+ let gripStubs = new Map();
+ gripStubs.set("testSymbolFoo", {
+ type: "symbol",
+ name: "foo"
+ });
+ gripStubs.set("testSymbolWithoutIdentifier", {
+ type: "symbol"
+ });
+
+ try {
+ // Test that correct rep is chosen
+ const renderedRep = shallowRenderComponent(
+ Rep,
+ { object: gripStubs.get("testSymbolFoo")}
+ );
+
+ is(renderedRep.type, SymbolRep.rep,
+ `Rep correctly selects ${SymbolRep.rep.displayName}`);
+
+ // Test rendering
+ yield testSymbol();
+ yield testSymbolWithoutIdentifier();
+ } catch (e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+
+ function testSymbol() {
+ const renderedComponent = renderComponent(
+ SymbolRep.rep,
+ { object: gripStubs.get("testSymbolFoo") }
+ );
+
+ is(renderedComponent.textContent, "Symbol(foo)",
+ "Symbol rep has expected text content");
+ }
+
+ function testSymbolWithoutIdentifier() {
+ const renderedComponent = renderComponent(
+ SymbolRep.rep,
+ { object: gripStubs.get("testSymbolWithoutIdentifier") }
+ );
+
+ is(renderedComponent.textContent, "Symbol()",
+ "Symbol rep without identifier has expected text content");
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_reps_text-node.html b/devtools/client/shared/components/test/mochitest/test_reps_text-node.html
new file mode 100644
index 000000000..f64902a63
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_reps_text-node.html
@@ -0,0 +1,115 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test text-node rep
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Rep test - text-node</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+"use strict";
+
+window.onload = Task.async(function* () {
+ let { Rep } = browserRequire("devtools/client/shared/components/reps/rep");
+ let { TextNode } = browserRequire("devtools/client/shared/components/reps/text-node");
+
+ let gripStubs = new Map();
+ gripStubs.set("testRendering", {
+ "class": "Text",
+ "actor": "server1.conn1.child1/obj50",
+ "preview": {
+ "textContent": "hello world"
+ }
+ });
+ gripStubs.set("testRenderingWithEOL", {
+ "class": "Text",
+ "actor": "server1.conn1.child1/obj50",
+ "preview": {
+ "textContent": "hello\nworld"
+ }
+ });
+
+ try {
+ // Test that correct rep is chosen
+ const renderedRep = shallowRenderComponent(Rep, {
+ object: gripStubs.get("testRendering")
+ });
+
+ is(renderedRep.type, TextNode.rep,
+ `Rep correctly selects ${TextNode.rep.displayName}`);
+
+ yield testRendering();
+ yield testRenderingWithEOL();
+ } catch (e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+
+ function testRendering() {
+ const stub = gripStubs.get("testRendering");
+ const defaultShortOutput = `"hello world"`;
+ const defaultLongOutput = `<TextNode textContent="hello world">;`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultShortOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: defaultShortOutput,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultShortOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultLongOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, "testRendering", TextNode, stub);
+ }
+
+ function testRenderingWithEOL() {
+ const stub = gripStubs.get("testRenderingWithEOL");
+ const defaultShortOutput = `"hello\nworld"`;
+ const defaultLongOutput = `<TextNode textContent="hello\nworld">;`;
+
+ const modeTests = [
+ {
+ mode: undefined,
+ expectedOutput: defaultShortOutput,
+ },
+ {
+ mode: "tiny",
+ expectedOutput: defaultShortOutput,
+ },
+ {
+ mode: "short",
+ expectedOutput: defaultShortOutput,
+ },
+ {
+ mode: "long",
+ expectedOutput: defaultLongOutput,
+ }
+ ];
+
+ testRepRenderModes(modeTests, "testRenderingWithEOL", TextNode, stub);
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_reps_undefined.html b/devtools/client/shared/components/test/mochitest/test_reps_undefined.html
new file mode 100644
index 000000000..26b3345ac
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_reps_undefined.html
@@ -0,0 +1,47 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test undefined rep
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Rep test - undefined</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+window.onload = Task.async(function* () {
+ try {
+ let ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
+ let React = browserRequire("devtools/client/shared/vendor/react");
+ let { Rep } = browserRequire("devtools/client/shared/components/reps/rep");
+ let { Undefined } = browserRequire("devtools/client/shared/components/reps/undefined");
+
+ let gripStub = {
+ "type": "undefined"
+ };
+
+ // Test that correct rep is chosen
+ const renderedRep = shallowRenderComponent(Rep, { object: gripStub });
+ is(renderedRep.type, Undefined.rep, `Rep correctly selects ${Undefined.rep.displayName}`);
+
+ // Test rendering
+ const renderedComponent = renderComponent(Undefined.rep, {});
+ is(renderedComponent.className, "objectBox objectBox-undefined", "Undefined rep has expected class names");
+ is(renderedComponent.textContent, "undefined", "Undefined rep has expected text content");
+ } catch(e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_reps_window.html b/devtools/client/shared/components/test/mochitest/test_reps_window.html
new file mode 100644
index 000000000..55d60e9f5
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_reps_window.html
@@ -0,0 +1,58 @@
+<!-- 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/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test window rep
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Rep tests - window</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+window.onload = Task.async(function* () {
+ try {
+ let ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
+ let React = browserRequire("devtools/client/shared/vendor/react");
+ let { Rep } = browserRequire("devtools/client/shared/components/reps/rep");
+ let { Window } = browserRequire("devtools/client/shared/components/reps/window");
+
+ let gripStub = {
+ "type": "object",
+ "class": "Window",
+ "actor": "server1.conn3.obj198",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 887,
+ "preview": {
+ "kind": "ObjectWithURL",
+ "url": "about:newtab"
+ }
+ };
+
+ // Test that correct rep is chosen
+ const renderedRep = shallowRenderComponent(Rep, { object: gripStub });
+ is(renderedRep.type, Window.rep, `Rep correctly selects ${Window.rep.displayName}`);
+
+ // Test rendering
+ const renderedComponent = renderComponent(Window.rep, { object: gripStub });
+ ok(renderedComponent.className.includes("objectBox-Window"), "Window rep has expected class name");
+ const innerNode = renderedComponent.querySelector(".objectPropValue");
+ is(innerNode.textContent, "about:newtab", "Window rep has expected inner HTML structure and text content");
+ } catch(e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_sidebar_toggle.html b/devtools/client/shared/components/test/mochitest/test_sidebar_toggle.html
new file mode 100644
index 000000000..252f2fbb1
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_sidebar_toggle.html
@@ -0,0 +1,56 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test sidebar toggle button
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Sidebar toggle button test</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+window.onload = Task.async(function* () {
+ let SidebarToggle = browserRequire("devtools/client/shared/components/sidebar-toggle.js");
+
+ try {
+ yield test();
+ } catch(e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+
+ function test() {
+ const output1 = shallowRenderComponent(SidebarToggle, {
+ collapsed: false,
+ collapsePaneTitle: "Expand",
+ expandPaneTitle: "Collapse"
+ });
+
+ is(output1.type, "button", "Output is a button element");
+ is(output1.props.title, "Expand", "Proper title is set");
+ is(output1.props.className.indexOf("pane-collapsed"), -1,
+ "Proper class name is set");
+
+ const output2 = shallowRenderComponent(SidebarToggle, {
+ collapsed: true,
+ collapsePaneTitle: "Expand",
+ expandPaneTitle: "Collapse"
+ });
+
+ is(output2.props.title, "Collapse", "Proper title is set");
+ ok(output2.props.className.indexOf("pane-collapsed") >= 0,
+ "Proper class name is set");
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_stack-trace.html b/devtools/client/shared/components/test/mochitest/test_stack-trace.html
new file mode 100644
index 000000000..121316cb4
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_stack-trace.html
@@ -0,0 +1,102 @@
+<!-- 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/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test the rendering of a stack trace
+-->
+<head>
+ <meta charset="utf-8">
+ <title>StackTrace component test</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<script src="head.js"></script>
+<script>
+/* import-globals-from head.js */
+"use strict";
+
+window.onload = function () {
+ let ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
+ let React = browserRequire("devtools/client/shared/vendor/react");
+ let StackTrace = React.createFactory(
+ browserRequire("devtools/client/shared/components/stack-trace")
+ );
+ ok(StackTrace, "Got the StackTrace factory");
+
+ add_task(function* () {
+ let stacktrace = [
+ {
+ filename: "http://myfile.com/mahscripts.js",
+ lineNumber: 55,
+ columnNumber: 10
+ },
+ {
+ asyncCause: "because",
+ functionName: "loadFunc",
+ filename: "http://myfile.com/loader.js -> http://myfile.com/loadee.js",
+ lineNumber: 10
+ }
+ ];
+
+ let props = {
+ stacktrace,
+ onViewSourceInDebugger: () => {}
+ };
+
+ let trace = ReactDOM.render(StackTrace(props), window.document.body);
+ yield forceRender(trace);
+
+ let traceEl = trace.getDOMNode();
+ ok(traceEl, "Rendered StackTrace has an element");
+
+ // Get the child nodes and filter out the text-only whitespace ones
+ let frameEls = Array.from(traceEl.childNodes)
+ .filter(n => n.className.includes("frame"));
+ ok(frameEls, "Rendered StackTrace has frames");
+ is(frameEls.length, 3, "StackTrace has 3 frames");
+
+ // Check the top frame, function name should be anonymous
+ checkFrameString({
+ el: frameEls[0],
+ functionName: "<anonymous>",
+ source: "http://myfile.com/mahscripts.js",
+ file: "http://myfile.com/mahscripts.js",
+ line: 55,
+ column: 10,
+ shouldLink: true,
+ tooltip: "View source in Debugger → http://myfile.com/mahscripts.js:55:10",
+ });
+
+ // Check the async cause node
+ is(frameEls[1].className, "frame-link-async-cause",
+ "Async cause has the right class");
+ is(frameEls[1].textContent, "(Async: because)", "Async cause has the right label");
+
+ // Check the third frame, the source should be parsed into a valid source URL
+ checkFrameString({
+ el: frameEls[2],
+ functionName: "loadFunc",
+ source: "http://myfile.com/loadee.js",
+ file: "http://myfile.com/loadee.js",
+ line: 10,
+ column: null,
+ shouldLink: true,
+ tooltip: "View source in Debugger → http://myfile.com/loadee.js:10",
+ });
+
+ // Check the tabs and newlines in the stack trace textContent
+ let traceText = traceEl.textContent;
+ let traceLines = traceText.split("\n");
+ ok(traceLines.length > 0, "There are newlines in the stack trace text");
+ is(traceLines.pop(), "", "There is a newline at the end of the stack trace text");
+ is(traceLines.length, 3, "The stack trace text has 3 lines");
+ ok(traceLines.every(l => l[0] == "\t"), "Every stack trace line starts with tab");
+ });
+};
+</script>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_tabs_accessibility.html b/devtools/client/shared/components/test/mochitest/test_tabs_accessibility.html
new file mode 100644
index 000000000..a86082187
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_tabs_accessibility.html
@@ -0,0 +1,79 @@
+<!-- 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/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test tabs accessibility.
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Tabs component accessibility test</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+window.onload = Task.async(function* () {
+ try {
+ const ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
+ const React = browserRequire("devtools/client/shared/vendor/react");
+ const { Simulate } = React.addons.TestUtils;
+ const InspectorTabPanel = React.createFactory(browserRequire("devtools/client/inspector/components/inspector-tab-panel"));
+ const Tabbar = React.createFactory(browserRequire("devtools/client/shared/components/tabs/tabbar"));
+ const tabbar = Tabbar();
+ const tabbarReact = ReactDOM.render(tabbar, window.document.body);
+ const tabbarEl = ReactDOM.findDOMNode(tabbarReact);
+
+ // Setup for InspectorTabPanel
+ const tabpanels = document.createElement("div");
+ tabpanels.id = "tabpanels";
+ document.body.appendChild(tabpanels);
+
+ yield addTabWithPanel(0);
+ yield addTabWithPanel(1);
+
+ const tabAnchors = tabbarEl.querySelectorAll("li.tabs-menu-item a");
+
+ is(tabAnchors[0].parentElement.getAttribute("role"), "presentation", "li role is set correctly");
+ is(tabAnchors[0].getAttribute("role"), "tab", "Anchor role is set correctly");
+ is(tabAnchors[0].getAttribute("aria-selected"), "true", "Anchor aria-selected is set correctly by default");
+ is(tabAnchors[0].getAttribute("aria-controls"), "panel-0", "Anchor aria-controls is set correctly");
+ is(tabAnchors[1].parentElement.getAttribute("role"), "presentation", "li role is set correctly");
+ is(tabAnchors[1].getAttribute("role"), "tab", "Anchor role is set correctly");
+ is(tabAnchors[1].getAttribute("aria-selected"), "false", "Anchor aria-selected is set correctly by default");
+ is(tabAnchors[1].getAttribute("aria-controls"), "panel-1", "Anchor aria-controls is set correctly");
+
+ yield setState(tabbarReact, Object.assign({}, tabbarReact.state, {
+ activeTab: 1
+ }));
+
+ is(tabAnchors[0].getAttribute("aria-selected"), "false", "Anchor aria-selected is reset correctly");
+ is(tabAnchors[1].getAttribute("aria-selected"), "true", "Anchor aria-selected is reset correctly");
+
+ function addTabWithPanel(tabId) {
+ // Setup for InspectorTabPanel
+ let panel = document.createElement("div");
+ panel.id = `sidebar-panel-${tabId}`;
+ document.body.appendChild(panel);
+
+ return setState(tabbarReact, Object.assign({}, tabbarReact.state, {
+ tabs: tabbarReact.state.tabs.concat({
+ id: `sidebar-panel-${tabId}`,
+ title: `tab-${tabId}`,
+ panel: InspectorTabPanel
+ }),
+ }));
+ }
+ } catch(e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_tabs_menu.html b/devtools/client/shared/components/test/mochitest/test_tabs_menu.html
new file mode 100644
index 000000000..ac8e99289
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_tabs_menu.html
@@ -0,0 +1,81 @@
+<!-- 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/. -->
+<!DOCTYPE HTML>
+<html class="theme-light">
+<!--
+Test all-tabs menu.
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Tabs component All-tabs menu test</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+ <link rel="stylesheet" type="text/css" href="resource://devtools/client/themes/variables.css">
+ <link rel="stylesheet" type="text/css" href="resource://devtools/client/themes/common.css">
+ <link rel="stylesheet" type="text/css" href="resource://devtools/client/themes/light-theme.css">
+ <link rel="stylesheet" type="text/css" href="resource://devtools/client/shared/components/tabs/tabs.css">
+ <link rel="stylesheet" type="text/css" href="resource://devtools/client/shared/components/tabs/tabbar.css">
+ <link rel="stylesheet" type="text/css" href="resource://devtools/client/inspector/components/side-panel.css">
+ <link rel="stylesheet" type="text/css" href="resource://devtools/client/inspector/components/inspector-tab-panel.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+window.onload = Task.async(function* () {
+ try {
+ const ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
+ const React = browserRequire("devtools/client/shared/vendor/react");
+ const Tabbar = React.createFactory(browserRequire("devtools/client/shared/components/tabs/tabbar"));
+
+ // Create container for the TabBar. Set smaller width
+ // to ensure that tabs won't fit and the all-tabs menu
+ // needs to appear.
+ const tabBarBox = document.createElement("div");
+ tabBarBox.style.width = "200px";
+ tabBarBox.style.height = "200px";
+ tabBarBox.style.border = "1px solid lightgray";
+ document.body.appendChild(tabBarBox);
+
+ // Render the tab-bar.
+ const tabbar = Tabbar({
+ showAllTabsMenu: true,
+ });
+
+ const tabbarReact = ReactDOM.render(tabbar, tabBarBox);
+
+ // Test panel.
+ let TabPanel = React.createFactory(React.createClass({
+ render: function () {
+ return React.DOM.div({}, "content");
+ }
+ }));
+
+ // Create a few panels.
+ yield addTabWithPanel(1);
+ yield addTabWithPanel(2);
+ yield addTabWithPanel(3);
+ yield addTabWithPanel(4);
+ yield addTabWithPanel(5);
+
+ // Make sure the all-tabs menu is there.
+ const allTabsMenu = tabBarBox.querySelector(".all-tabs-menu");
+ ok(allTabsMenu, "All-tabs menu must be rendered");
+
+ function addTabWithPanel(tabId) {
+ return setState(tabbarReact, Object.assign({}, tabbarReact.state, {
+ tabs: tabbarReact.state.tabs.concat({id: `${tabId}`,
+ title: `tab-${tabId}`, panel: TabPanel}),
+ }));
+ }
+ } catch(e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_tree_01.html b/devtools/client/shared/components/test/mochitest/test_tree_01.html
new file mode 100644
index 000000000..dfd666348
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_tree_01.html
@@ -0,0 +1,64 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test trees get displayed with the items in correct order and at the correct
+depth.
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Tree component test</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+window.onload = Task.async(function* () {
+ try {
+ let ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
+ let React = browserRequire("devtools/client/shared/vendor/react");
+ let Tree = React.createFactory(browserRequire("devtools/client/shared/components/tree"));
+
+ ok(React, "Should get React");
+ ok(Tree, "Should get Tree");
+
+ const t = Tree(TEST_TREE_INTERFACE);
+ ok(t, "Should be able to create Tree instances");
+
+ const tree = ReactDOM.render(t, window.document.body);
+ ok(tree, "Should be able to mount Tree instances");
+
+ TEST_TREE.expanded = new Set("ABCDEFGHIJKLMNO".split(""));
+ yield forceRender(tree);
+
+ isRenderedTree(document.body.textContent, [
+ "A:false",
+ "-B:false",
+ "--E:false",
+ "---K:false",
+ "---L:false",
+ "--F:false",
+ "--G:false",
+ "-C:false",
+ "--H:false",
+ "--I:false",
+ "-D:false",
+ "--J:false",
+ "M:false",
+ "-N:false",
+ "--O:false",
+ ], "Should get the items rendered and indented as expected");
+ } catch(e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_tree_02.html b/devtools/client/shared/components/test/mochitest/test_tree_02.html
new file mode 100644
index 000000000..a1fc33a38
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_tree_02.html
@@ -0,0 +1,45 @@
+<!-- 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/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test that collapsed subtrees aren't rendered.
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Tree component test</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+window.onload = Task.async(function* () {
+ try {
+ let ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
+ let React = browserRequire("devtools/client/shared/vendor/react");
+ let Tree = React.createFactory(browserRequire("devtools/client/shared/components/tree"));
+
+ const tree = ReactDOM.render(Tree(TEST_TREE_INTERFACE), window.document.body);
+
+ TEST_TREE.expanded = new Set("MNO".split(""));
+ yield forceRender(tree);
+
+ isRenderedTree(document.body.textContent, [
+ "A:false",
+ "M:false",
+ "-N:false",
+ "--O:false",
+ ], "Collapsed subtrees shouldn't be rendered");
+ } catch(e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_tree_03.html b/devtools/client/shared/components/test/mochitest/test_tree_03.html
new file mode 100644
index 000000000..feabc7e0a
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_tree_03.html
@@ -0,0 +1,46 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test Tree's autoExpandDepth.
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Tree component test</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+window.onload = Task.async(function* () {
+ try {
+ let ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
+ let React = browserRequire("devtools/client/shared/vendor/react");
+ let Tree = React.createFactory(browserRequire("devtools/client/shared/components/tree"));
+
+ const tree = ReactDOM.render(Tree(Object.assign({}, TEST_TREE_INTERFACE, {
+ autoExpandDepth: 1
+ })), window.document.body);
+
+ isRenderedTree(document.body.textContent, [
+ "A:false",
+ "-B:false",
+ "-C:false",
+ "-D:false",
+ "M:false",
+ "-N:false",
+ ], "Tree should be auto expanded one level");
+ } catch(e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_tree_04.html b/devtools/client/shared/components/test/mochitest/test_tree_04.html
new file mode 100644
index 000000000..24948c003
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_tree_04.html
@@ -0,0 +1,128 @@
+<!-- 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/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test that we only render visible tree items.
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Tree component test</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+window.onload = Task.async(function* () {
+ try {
+ function getSpacerHeights() {
+ return {
+ top: document.querySelector(".tree > div:first-of-type").clientHeight,
+ bottom: document.querySelector(".tree > div:last-of-type").clientHeight,
+ };
+ }
+
+ const ITEM_HEIGHT = 3;
+
+ const ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
+ const React = browserRequire("devtools/client/shared/vendor/react");
+ const Tree = React.createFactory(browserRequire("devtools/client/shared/components/tree"));
+
+ const tree = ReactDOM.render(
+ Tree(Object.assign({}, TEST_TREE_INTERFACE, { itemHeight: ITEM_HEIGHT })),
+ window.document.body);
+
+ TEST_TREE.expanded = new Set("ABCDEFGHIJKLMNO".split(""));
+
+ yield setState(tree, {
+ height: 3 * ITEM_HEIGHT,
+ scroll: 1 * ITEM_HEIGHT
+ });
+
+ isRenderedTree(document.body.textContent, [
+ "A:false",
+ "-B:false",
+ "--E:false",
+ "---K:false",
+ "---L:false",
+ ], "Tree should show the 2nd, 3rd, and 4th items + buffer of 1 item at each end");
+
+ let spacers = getSpacerHeights();
+ is(spacers.top, 0, "Top spacer has the correct height");
+ is(spacers.bottom, 10 * ITEM_HEIGHT, "Bottom spacer has the correct height");
+
+ yield setState(tree, {
+ height: 2 * ITEM_HEIGHT,
+ scroll: 3 * ITEM_HEIGHT
+ });
+
+ isRenderedTree(document.body.textContent, [
+ "--E:false",
+ "---K:false",
+ "---L:false",
+ "--F:false",
+ ], "Tree should show the 4th and 5th item + buffer of 1 item at each end");
+
+ spacers = getSpacerHeights();
+ is(spacers.top, 2 * ITEM_HEIGHT, "Top spacer has the correct height");
+ is(spacers.bottom, 9 * ITEM_HEIGHT, "Bottom spacer has the correct height");
+
+ // Set height to 2 items + 1 pixel at each end, scroll so that 4 items are visible
+ // (2 fully, 2 partially with 1 visible pixel)
+ yield setState(tree, {
+ height: 2 * ITEM_HEIGHT + 2,
+ scroll: 3 * ITEM_HEIGHT - 1
+ });
+
+ isRenderedTree(document.body.textContent, [
+ "-B:false",
+ "--E:false",
+ "---K:false",
+ "---L:false",
+ "--F:false",
+ "--G:false",
+ ], "Tree should show the 4 visible items + buffer of 1 item at each end");
+
+ spacers = getSpacerHeights();
+ is(spacers.top, 1 * ITEM_HEIGHT, "Top spacer has the correct height");
+ is(spacers.bottom, 8 * ITEM_HEIGHT, "Bottom spacer has the correct height");
+
+ yield setState(tree, {
+ height: 20 * ITEM_HEIGHT,
+ scroll: 0
+ });
+
+ isRenderedTree(document.body.textContent, [
+ "A:false",
+ "-B:false",
+ "--E:false",
+ "---K:false",
+ "---L:false",
+ "--F:false",
+ "--G:false",
+ "-C:false",
+ "--H:false",
+ "--I:false",
+ "-D:false",
+ "--J:false",
+ "M:false",
+ "-N:false",
+ "--O:false",
+ ], "Tree should show all rows");
+
+ spacers = getSpacerHeights();
+ is(spacers.top, 0, "Top spacer has zero height");
+ is(spacers.bottom, 0, "Bottom spacer has zero height");
+ } catch(e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_tree_05.html b/devtools/client/shared/components/test/mochitest/test_tree_05.html
new file mode 100644
index 000000000..76116ab51
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_tree_05.html
@@ -0,0 +1,83 @@
+<!-- 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/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test focusing with the Tree component.
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Tree component test</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+
+window.onload = Task.async(function* () {
+ try {
+ const ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
+ const React = browserRequire("devtools/client/shared/vendor/react");
+ const { Simulate } = React.addons.TestUtils;
+ const Tree = React.createFactory(browserRequire("devtools/client/shared/components/tree"));
+ const tree = ReactDOM.render(Tree(Object.assign({}, TEST_TREE_INTERFACE, {
+ onFocus: x => setProps(tree, { focused: x }),
+ })), window.document.body);
+
+ TEST_TREE.expanded = new Set("ABCDEFGHIJKLMNO".split(""));
+ yield setProps(tree, {
+ focused: "G",
+ });
+
+ isRenderedTree(document.body.textContent, [
+ "A:false",
+ "-B:false",
+ "--E:false",
+ "---K:false",
+ "---L:false",
+ "--F:false",
+ "--G:true",
+ "-C:false",
+ "--H:false",
+ "--I:false",
+ "-D:false",
+ "--J:false",
+ "M:false",
+ "-N:false",
+ "--O:false",
+ ], "G should be focused");
+
+ // Click the first tree node
+ Simulate.click(document.querySelector(".tree-node"));
+ yield forceRender(tree);
+
+ isRenderedTree(document.body.textContent, [
+ "A:true",
+ "-B:false",
+ "--E:false",
+ "---K:false",
+ "---L:false",
+ "--F:false",
+ "--G:false",
+ "-C:false",
+ "--H:false",
+ "--I:false",
+ "-D:false",
+ "--J:false",
+ "M:false",
+ "-N:false",
+ "--O:false",
+ ], "A should be focused");
+ } catch(e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_tree_06.html b/devtools/client/shared/components/test/mochitest/test_tree_06.html
new file mode 100644
index 000000000..1d8f28ec9
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_tree_06.html
@@ -0,0 +1,320 @@
+<!-- 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/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test keyboard navigation with the Tree component.
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Tree component test</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+window.onload = Task.async(function* () {
+ try {
+ const ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
+ const React = browserRequire("devtools/client/shared/vendor/react");
+ const { Simulate } = React.addons.TestUtils;
+ const Tree = React.createFactory(browserRequire("devtools/client/shared/components/tree"));
+ const tree = ReactDOM.render(Tree(Object.assign({}, TEST_TREE_INTERFACE, {
+ onFocus: x => setProps(tree, { focused: x }),
+ })), window.document.body);
+
+ TEST_TREE.expanded = new Set("ABCDEFGHIJKLMNO".split(""));
+
+ // UP ----------------------------------------------------------------------
+
+ info("Up to the previous sibling.");
+
+ yield setProps(tree, {
+ focused: "L"
+ });
+ Simulate.keyDown(document.querySelector(".tree"), { key: "ArrowUp" });
+ yield forceRender(tree);
+
+ isRenderedTree(document.body.textContent, [
+ "A:false",
+ "-B:false",
+ "--E:false",
+ "---K:true",
+ "---L:false",
+ "--F:false",
+ "--G:false",
+ "-C:false",
+ "--H:false",
+ "--I:false",
+ "-D:false",
+ "--J:false",
+ "M:false",
+ "-N:false",
+ "--O:false",
+ ], "After the UP, K should be focused.");
+
+ info("Up to the parent.");
+
+ Simulate.keyDown(document.querySelector(".tree"), { key: "ArrowUp" });
+ yield forceRender(tree);
+
+ isRenderedTree(document.body.textContent, [
+ "A:false",
+ "-B:false",
+ "--E:true",
+ "---K:false",
+ "---L:false",
+ "--F:false",
+ "--G:false",
+ "-C:false",
+ "--H:false",
+ "--I:false",
+ "-D:false",
+ "--J:false",
+ "M:false",
+ "-N:false",
+ "--O:false",
+ ], "After the UP, E should be focused.");
+
+ info("Try and navigate up, past the first item.");
+
+ yield setProps(tree, {
+ focused: "A"
+ });
+ Simulate.keyDown(document.querySelector(".tree"), { key: "ArrowUp" });
+ yield forceRender(tree);
+
+ isRenderedTree(document.body.textContent, [
+ "A:true",
+ "-B:false",
+ "--E:false",
+ "---K:false",
+ "---L:false",
+ "--F:false",
+ "--G:false",
+ "-C:false",
+ "--H:false",
+ "--I:false",
+ "-D:false",
+ "--J:false",
+ "M:false",
+ "-N:false",
+ "--O:false",
+ ], "After the UP, A should be focused and we shouldn't have overflowed past it.");
+
+ // DOWN --------------------------------------------------------------------
+
+ yield setProps(tree, {
+ focused: "K"
+ });
+
+ info("Down to next sibling.");
+
+ Simulate.keyDown(document.querySelector(".tree"), { key: "ArrowDown" });
+ yield forceRender(tree);
+
+ isRenderedTree(document.body.textContent, [
+ "A:false",
+ "-B:false",
+ "--E:false",
+ "---K:false",
+ "---L:true",
+ "--F:false",
+ "--G:false",
+ "-C:false",
+ "--H:false",
+ "--I:false",
+ "-D:false",
+ "--J:false",
+ "M:false",
+ "-N:false",
+ "--O:false",
+ ], "After the DOWN, L should be focused.");
+
+ info("Down to parent's next sibling.");
+
+ Simulate.keyDown(document.querySelector(".tree"), { key: "ArrowDown" });
+ yield forceRender(tree);
+
+ isRenderedTree(document.body.textContent, [
+ "A:false",
+ "-B:false",
+ "--E:false",
+ "---K:false",
+ "---L:false",
+ "--F:true",
+ "--G:false",
+ "-C:false",
+ "--H:false",
+ "--I:false",
+ "-D:false",
+ "--J:false",
+ "M:false",
+ "-N:false",
+ "--O:false",
+ ], "After the DOWN, F should be focused.");
+
+ info("Try and go down past the last item.");
+
+ yield setProps(tree, {
+ focused: "O"
+ });
+ Simulate.keyDown(document.querySelector(".tree"), { key: "ArrowDown" });
+ yield forceRender(tree);
+
+ isRenderedTree(document.body.textContent, [
+ "A:false",
+ "-B:false",
+ "--E:false",
+ "---K:false",
+ "---L:false",
+ "--F:false",
+ "--G:false",
+ "-C:false",
+ "--H:false",
+ "--I:false",
+ "-D:false",
+ "--J:false",
+ "M:false",
+ "-N:false",
+ "--O:true",
+ ], "After the DOWN, O should still be focused and we shouldn't have overflowed past it.");
+
+ // LEFT --------------------------------------------------------------------
+
+ info("Left to go to parent.");
+
+ yield setProps(tree, {
+ focused: "L"
+ })
+ Simulate.keyDown(document.querySelector(".tree"), { key: "ArrowLeft" });
+ yield forceRender(tree);
+
+ isRenderedTree(document.body.textContent, [
+ "A:false",
+ "-B:false",
+ "--E:true",
+ "---K:false",
+ "---L:false",
+ "--F:false",
+ "--G:false",
+ "-C:false",
+ "--H:false",
+ "--I:false",
+ "-D:false",
+ "--J:false",
+ "M:false",
+ "-N:false",
+ "--O:false",
+ ], "After the LEFT, E should be focused.");
+
+ info("Left to collapse children.");
+
+ Simulate.keyDown(document.querySelector(".tree"), { key: "ArrowLeft" });
+ yield forceRender(tree);
+
+ isRenderedTree(document.body.textContent, [
+ "A:false",
+ "-B:false",
+ "--E:true",
+ "--F:false",
+ "--G:false",
+ "-C:false",
+ "--H:false",
+ "--I:false",
+ "-D:false",
+ "--J:false",
+ "M:false",
+ "-N:false",
+ "--O:false",
+ ], "After the LEFT, E's children should be collapsed.");
+
+ // RIGHT -------------------------------------------------------------------
+
+ info("Right to expand children.");
+
+ Simulate.keyDown(document.querySelector(".tree"), { key: "ArrowRight" });
+ yield forceRender(tree);
+
+ isRenderedTree(document.body.textContent, [
+ "A:false",
+ "-B:false",
+ "--E:true",
+ "---K:false",
+ "---L:false",
+ "--F:false",
+ "--G:false",
+ "-C:false",
+ "--H:false",
+ "--I:false",
+ "-D:false",
+ "--J:false",
+ "M:false",
+ "-N:false",
+ "--O:false",
+ ], "After the RIGHT, E's children should be expanded again.");
+
+ info("Right to go to next item.");
+
+ Simulate.keyDown(document.querySelector(".tree"), { key: "ArrowRight" });
+ yield forceRender(tree);
+
+ isRenderedTree(document.body.textContent, [
+ "A:false",
+ "-B:false",
+ "--E:false",
+ "---K:true",
+ "---L:false",
+ "--F:false",
+ "--G:false",
+ "-C:false",
+ "--H:false",
+ "--I:false",
+ "-D:false",
+ "--J:false",
+ "M:false",
+ "-N:false",
+ "--O:false",
+ ], "After the RIGHT, K should be focused.");
+
+ // Check that keys are ignored if any modifier is present.
+ let keysWithModifier = [
+ { key: "ArrowDown", altKey: true },
+ { key: "ArrowDown", ctrlKey: true },
+ { key: "ArrowDown", metaKey: true },
+ { key: "ArrowDown", shiftKey: true },
+ ];
+ for (let key of keysWithModifier) {
+ Simulate.keyDown(document.querySelector(".tree"), key);
+ yield forceRender(tree);
+ isRenderedTree(document.body.textContent, [
+ "A:false",
+ "-B:false",
+ "--E:false",
+ "---K:true",
+ "---L:false",
+ "--F:false",
+ "--G:false",
+ "-C:false",
+ "--H:false",
+ "--I:false",
+ "-D:false",
+ "--J:false",
+ "M:false",
+ "-N:false",
+ "--O:false",
+ ], "After DOWN + (alt|ctrl|meta|shift), K should remain focused.");
+ }
+ } catch(e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_tree_07.html b/devtools/client/shared/components/test/mochitest/test_tree_07.html
new file mode 100644
index 000000000..178ac77e3
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_tree_07.html
@@ -0,0 +1,64 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test that arrows get the open attribute when their item's children are expanded.
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Tree component test</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+ <link rel="stylesheet" href="chrome://devtools/skin/light-theme.css" type="text/css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+window.onload = Task.async(function* () {
+ try {
+ const ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
+ const React = browserRequire("devtools/client/shared/vendor/react");
+ const Tree = React.createFactory(browserRequire("devtools/client/shared/components/tree"));
+ const tree = ReactDOM.render(Tree(TEST_TREE_INTERFACE), window.document.body);
+
+ yield setProps(tree, {
+ renderItem: (item, depth, focused, arrow) => {
+ return React.DOM.div(
+ {
+ id: item,
+ style: { marginLeft: depth * 16 + "px" }
+ },
+ arrow,
+ item
+ );
+ }
+ });
+
+ TEST_TREE.expanded = new Set("ABCDEFGHIJKLMNO".split(""));
+ yield forceRender(tree);
+
+ let arrows = document.querySelectorAll(".arrow");
+ for (let a of arrows) {
+ ok(a.classList.contains("open"), "Every arrow should be open.");
+ }
+
+ TEST_TREE.expanded = new Set();
+ yield forceRender(tree);
+
+ arrows = document.querySelectorAll(".arrow");
+ for (let a of arrows) {
+ ok(!a.classList.contains("open"), "Every arrow should be closed.");
+ }
+ } catch(e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_tree_08.html b/devtools/client/shared/components/test/mochitest/test_tree_08.html
new file mode 100644
index 000000000..d024f37f8
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_tree_08.html
@@ -0,0 +1,51 @@
+<!-- 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/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test that when an item in the Tree component is clicked, it steals focus from
+other inputs.
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Tree component test</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+ <link rel="stylesheet" href="chrome://devtools/skin/light-theme.css" type="text/css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+window.onload = Task.async(function* () {
+ try {
+ const ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
+ const React = browserRequire("devtools/client/shared/vendor/react");
+ const { Simulate } = React.addons.TestUtils;
+ const Tree = React.createFactory(browserRequire("devtools/client/shared/components/tree"));
+ const tree = ReactDOM.render(Tree(Object.assign({}, TEST_TREE_INTERFACE, {
+ onFocus: x => setProps(tree, { focused: x }),
+ })), window.document.body);
+
+ const input = document.createElement("input");
+ document.body.appendChild(input);
+
+ input.focus();
+ is(document.activeElement, input, "The text input should be focused.");
+
+ Simulate.click(document.querySelector(".tree-node"));
+ yield forceRender(tree);
+
+ isnot(document.activeElement, input,
+ "The input should have had it's focus stolen by clicking on a tree item.");
+ } catch(e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_tree_09.html b/devtools/client/shared/components/test/mochitest/test_tree_09.html
new file mode 100644
index 000000000..96650134b
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_tree_09.html
@@ -0,0 +1,77 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test that when an item in the Tree component is expanded or collapsed the appropriate event handler fires.
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Tree component test</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+ <link rel="stylesheet" href="chrome://devtools/skin/light-theme.css" type="text/css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+window.onload = Task.async(function* () {
+ try {
+ const ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
+ const React = browserRequire("devtools/client/shared/vendor/react");
+ const { Simulate } = React.addons.TestUtils;
+ const Tree = React.createFactory(browserRequire("devtools/client/shared/components/tree"));
+
+ let numberOfExpands = 0;
+ let lastExpandedItem = null;
+
+ let numberOfCollapses = 0;
+ let lastCollapsedItem = null;
+
+ const tree = ReactDOM.render(Tree(Object.assign({}, TEST_TREE_INTERFACE, {
+ autoExpandDepth: 0,
+ onExpand: item => {
+ lastExpandedItem = item;
+ numberOfExpands++;
+ TEST_TREE.expanded.add(item);
+ },
+ onCollapse: item => {
+ lastCollapsedItem = item;
+ numberOfCollapses++;
+ TEST_TREE.expanded.delete(item);
+ },
+ onFocus: item => setProps(tree, { focused: item }),
+ })), window.document.body);
+
+ yield setProps(tree, {
+ focused: "A"
+ });
+
+ is(lastExpandedItem, null);
+ is(lastCollapsedItem, null);
+
+ // Expand "A" via the keyboard and then let the component re-render.
+ Simulate.keyDown(document.querySelector(".tree"), { key: "ArrowRight" });
+ yield forceRender(tree);
+
+ is(lastExpandedItem, "A", "Our onExpand callback should have been fired.");
+ is(numberOfExpands, 1);
+
+ // Now collapse "A" via the keyboard and then let the component re-render.
+ Simulate.keyDown(document.querySelector(".tree"), { key: "ArrowLeft" });
+ yield forceRender(tree);
+
+ is(lastCollapsedItem, "A", "Our onCollapsed callback should have been fired.");
+ is(numberOfCollapses, 1);
+ } catch(e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_tree_10.html b/devtools/client/shared/components/test/mochitest/test_tree_10.html
new file mode 100644
index 000000000..34f8a2633
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_tree_10.html
@@ -0,0 +1,52 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test that when an item in the Tree component is expanded or collapsed the appropriate event handler fires.
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Tree component test</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+ <link rel="stylesheet" href="chrome://devtools/skin/light-theme.css" type="text/css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+window.onload = Task.async(function* () {
+ try {
+ const ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
+ const React = browserRequire("devtools/client/shared/vendor/react");
+ const { Simulate } = React.addons.TestUtils;
+ const Tree = React.createFactory(browserRequire("devtools/client/shared/components/tree"));
+
+ const tree = ReactDOM.render(Tree(Object.assign({
+ autoExpandDepth: 1
+ }, TEST_TREE_INTERFACE)), window.document.body);
+
+ yield setProps(tree, {
+ focused: "A"
+ });
+
+ isRenderedTree(document.body.textContent, [
+ "A:true",
+ "-B:false",
+ "-C:false",
+ "-D:false",
+ "M:false",
+ "-N:false",
+ ], "Should have auto-expanded one level.");
+ } catch(e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/devtools/client/shared/components/test/mochitest/test_tree_11.html b/devtools/client/shared/components/test/mochitest/test_tree_11.html
new file mode 100644
index 000000000..1611f7d26
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_tree_11.html
@@ -0,0 +1,92 @@
+<!-- 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/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test that when an item in the Tree component is focused by arrow key, the view is scrolled.
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Tree component test</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+ <link rel="stylesheet" href="chrome://devtools/skin/light-theme.css" type="text/css">
+ <style>
+ * {
+ margin: 0;
+ padding: 0;
+ height: 30px;
+ max-height: 30px;
+ min-height: 30px;
+ font-size: 10px;
+ overflow: auto;
+ }
+ </style>
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+window.onload = Task.async(function* () {
+ try {
+ const ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
+ const React = browserRequire("devtools/client/shared/vendor/react");
+ const { Simulate } = React.addons.TestUtils;
+ const Tree = React.createFactory(browserRequire("devtools/client/shared/components/tree"));
+
+ TEST_TREE.expanded = new Set("ABCDEFGHIJKLMNO".split(""));
+
+ const tree = ReactDOM.render(Tree(TEST_TREE_INTERFACE), window.document.body);
+
+ yield setProps(tree, {
+ itemHeight: 10,
+ onFocus: item => setProps(tree, { focused: item }),
+ focused: "K",
+ });
+ yield setState(tree, {
+ scroll: 10,
+ });
+ yield forceRender(tree);
+
+ isRenderedTree(document.body.textContent, [
+ "A:false",
+ "-B:false",
+ "--E:false",
+ "---K:true",
+ "---L:false",
+ ], "Should render initial correctly");
+
+ yield new Promise(resolve => {
+ const treeElem = document.querySelector(".tree");
+ treeElem.addEventListener("scroll", function onScroll() {
+ dumpn("Got scroll event");
+ treeElem.removeEventListener("scroll", onScroll);
+ resolve();
+ });
+
+ dumpn("Sending ArrowDown key");
+ Simulate.keyDown(treeElem, { key: "ArrowDown" });
+ });
+
+ dumpn("Forcing re-render");
+ yield forceRender(tree);
+
+ isRenderedTree(document.body.textContent, [
+ "-B:false",
+ "--E:false",
+ "---K:false",
+ "---L:true",
+ "--F:false",
+ ], "Should have scrolled down one");
+
+ } catch(e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+});
+</script>
+</pre>
+</body>
+</html>