diff options
Diffstat (limited to 'devtools/client/shared/components/test')
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> |