diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
commit | 6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /devtools/client/memory/test/chrome | |
parent | Initial commit. (diff) | |
download | thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.tar.xz thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'devtools/client/memory/test/chrome')
18 files changed, 1505 insertions, 0 deletions
diff --git a/devtools/client/memory/test/chrome/chrome.ini b/devtools/client/memory/test/chrome/chrome.ini new file mode 100644 index 0000000000..7803bcda35 --- /dev/null +++ b/devtools/client/memory/test/chrome/chrome.ini @@ -0,0 +1,20 @@ +[DEFAULT] +support-files = + head.js + +[test_CensusTreeItem_01.html] +[test_DominatorTree_01.html] +[test_DominatorTree_02.html] +[test_DominatorTree_03.html] +[test_DominatorTreeItem_01.html] +[test_Heap_01.html] +[test_Heap_02.html] +[test_Heap_03.html] +[test_Heap_04.html] +[test_Heap_05.html] +[test_List_01.html] +[test_ShortestPaths_01.html] +[test_ShortestPaths_02.html] +[test_SnapshotListItem_01.html] +[test_Toolbar_01.html] +[test_TreeMap_01.html] diff --git a/devtools/client/memory/test/chrome/head.js b/devtools/client/memory/test/chrome/head.js new file mode 100644 index 0000000000..685fa62928 --- /dev/null +++ b/devtools/client/memory/test/chrome/head.js @@ -0,0 +1,354 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +var { BrowserLoader } = ChromeUtils.import( + "resource://devtools/shared/loader/browser-loader.js" +); +var { require } = BrowserLoader({ + baseURI: "resource://devtools/client/memory/", + window, +}); +var { Assert } = ChromeUtils.importESModule( + "resource://testing-common/Assert.sys.mjs" +); + +var EXPECTED_DTU_ASSERT_FAILURE_COUNT = 0; + +SimpleTest.registerCleanupFunction(function () { + if ( + DevToolsUtils.assertionFailureCount !== EXPECTED_DTU_ASSERT_FAILURE_COUNT + ) { + ok( + false, + "Should have had the expected number of DevToolsUtils.assert() failures." + + "Expected " + + EXPECTED_DTU_ASSERT_FAILURE_COUNT + + ", got " + + DevToolsUtils.assertionFailureCount + ); + } +}); + +var DevToolsUtils = require("resource://devtools/shared/DevToolsUtils.js"); +var { immutableUpdate } = DevToolsUtils; + +var constants = require("resource://devtools/client/memory/constants.js"); +var { + censusDisplays, + diffingState, + labelDisplays, + dominatorTreeState, + snapshotState, + viewState, + censusState, +} = constants; + +const { L10N } = require("resource://devtools/client/memory/utils.js"); + +var models = require("resource://devtools/client/memory/models.js"); + +var Immutable = require("resource://devtools/client/shared/vendor/immutable.js"); +var React = require("resource://devtools/client/shared/vendor/react.js"); +const dom = require("resource://devtools/client/shared/vendor/react-dom-factories.js"); +var ReactDOM = require("resource://devtools/client/shared/vendor/react-dom.js"); +var { createFactory } = React; +var Heap = createFactory( + require("resource://devtools/client/memory/components/Heap.js") +); +var CensusTreeItem = createFactory( + require("resource://devtools/client/memory/components/CensusTreeItem.js") +); +var DominatorTreeComponent = createFactory( + require("resource://devtools/client/memory/components/DominatorTree.js") +); +var DominatorTreeItem = createFactory( + require("resource://devtools/client/memory/components/DominatorTreeItem.js") +); +var ShortestPaths = createFactory( + require("resource://devtools/client/memory/components/ShortestPaths.js") +); +var TreeMap = createFactory( + require("resource://devtools/client/memory/components/TreeMap.js") +); +var SnapshotListItem = createFactory( + require("resource://devtools/client/memory/components/SnapshotListItem.js") +); +var List = createFactory( + require("resource://devtools/client/memory/components/List.js") +); +var Toolbar = createFactory( + require("resource://devtools/client/memory/components/Toolbar.js") +); + +// All tests are asynchronous. +SimpleTest.waitForExplicitFinish(); + +var noop = () => {}; + +var TEST_CENSUS_TREE_ITEM_PROPS = Object.freeze({ + item: Object.freeze({ + bytes: 10, + count: 1, + totalBytes: 10, + totalCount: 1, + name: "foo", + children: [ + Object.freeze({ + bytes: 10, + count: 1, + totalBytes: 10, + totalCount: 1, + name: "bar", + }), + ], + }), + depth: 0, + arrow: ">", + focused: true, + getPercentBytes: () => 50, + getPercentCount: () => 50, + showSign: false, + onViewSourceInDebugger: noop, + inverted: false, +}); + +// Counter for mock DominatorTreeNode ids. +var TEST_NODE_ID_COUNTER = 0; + +/** + * Create a mock DominatorTreeNode for testing, with sane defaults. Override any + * property by providing it on `opts`. Optionally pass child nodes as well. + * + * @param {Object} opts + * @param {Array<DominatorTreeNode>?} children + * + * @returns {DominatorTreeNode} + */ +function makeTestDominatorTreeNode(opts, children) { + const nodeId = TEST_NODE_ID_COUNTER++; + + const node = Object.assign( + { + nodeId, + label: ["other", "SomeType"], + shallowSize: 1, + retainedSize: (children || []).reduce( + (size, c) => size + c.retainedSize, + 1 + ), + parentId: undefined, + children, + moreChildrenAvailable: true, + }, + opts + ); + + if (children && children.length) { + children.map(c => { + c.parentId = node.nodeId; + }); + } + + return node; +} + +var TEST_DOMINATOR_TREE = Object.freeze({ + dominatorTreeId: 666, + root: (function makeTree(depth = 0) { + let children; + if (depth <= 3) { + children = [ + makeTree(depth + 1), + makeTree(depth + 1), + makeTree(depth + 1), + ]; + } + return makeTestDominatorTreeNode({}, children); + })(), + expanded: new Set(), + focused: null, + error: null, + display: labelDisplays.coarseType, + activeFetchRequestCount: null, + state: dominatorTreeState.LOADED, +}); + +var TEST_DOMINATOR_TREE_PROPS = Object.freeze({ + dominatorTree: TEST_DOMINATOR_TREE, + onLoadMoreSiblings: noop, + onViewSourceInDebugger: noop, + onExpand: noop, + onCollapse: noop, +}); + +var TEST_SHORTEST_PATHS_PROPS = Object.freeze({ + graph: Object.freeze({ + nodes: [ + { id: 1, label: ["other", "SomeType"] }, + { id: 2, label: ["other", "SomeType"] }, + { id: 3, label: ["other", "SomeType"] }, + ], + edges: [ + { from: 1, to: 2, name: "1->2" }, + { from: 1, to: 3, name: "1->3" }, + { from: 2, to: 3, name: "2->3" }, + ], + }), +}); + +var TEST_SNAPSHOT = Object.freeze({ + id: 1337, + selected: true, + path: "/fake/path/to/snapshot", + census: Object.freeze({ + report: Object.freeze({ + objects: Object.freeze({ count: 4, bytes: 400 }), + scripts: Object.freeze({ count: 3, bytes: 300 }), + strings: Object.freeze({ count: 2, bytes: 200 }), + other: Object.freeze({ count: 1, bytes: 100 }), + }), + display: Object.freeze({ + displayName: "Test Display", + tooltip: "Test display tooltup", + inverted: false, + breakdown: Object.freeze({ + by: "coarseType", + objects: Object.freeze({ by: "count", count: true, bytes: true }), + scripts: Object.freeze({ by: "count", count: true, bytes: true }), + strings: Object.freeze({ by: "count", count: true, bytes: true }), + other: Object.freeze({ by: "count", count: true, bytes: true }), + }), + }), + state: censusState.SAVED, + inverted: false, + filter: null, + expanded: new Set(), + focused: null, + parentMap: Object.freeze(Object.create(null)), + }), + dominatorTree: TEST_DOMINATOR_TREE, + error: null, + imported: false, + creationTime: 0, + state: snapshotState.READ, +}); + +var TEST_HEAP_PROPS = Object.freeze({ + onSnapshotClick: noop, + onLoadMoreSiblings: noop, + onCensusExpand: noop, + onCensusCollapse: noop, + onDominatorTreeExpand: noop, + onDominatorTreeCollapse: noop, + onCensusFocus: noop, + onDominatorTreeFocus: noop, + onViewSourceInDebugger: noop, + diffing: null, + view: { state: viewState.CENSUS }, + snapshot: TEST_SNAPSHOT, + sizes: Object.freeze({ shortestPathsSize: 0.5 }), + onShortestPathsResize: noop, +}); + +var TEST_TOOLBAR_PROPS = Object.freeze({ + censusDisplays: [ + censusDisplays.coarseType, + censusDisplays.allocationStack, + censusDisplays.invertedAllocationStack, + ], + censusDisplay: censusDisplays.coarseType, + onTakeSnapshotClick: noop, + onImportClick: noop, + onCensusDisplayChange: noop, + onToggleRecordAllocationStacks: noop, + allocations: models.allocations, + onToggleInverted: noop, + inverted: false, + filterString: null, + setFilterString: noop, + diffing: null, + onToggleDiffing: noop, + view: { state: viewState.CENSUS }, + onViewChange: noop, + labelDisplays: [labelDisplays.coarseType, labelDisplays.allocationStack], + labelDisplay: labelDisplays.coarseType, + onLabelDisplayChange: noop, + snapshots: [], +}); + +function makeTestCensusNode() { + return { + name: "Function", + bytes: 100, + totalBytes: 100, + count: 100, + totalCount: 100, + children: [], + }; +} + +var TEST_TREE_MAP_PROPS = Object.freeze({ + treeMap: Object.freeze({ + report: { + name: null, + bytes: 0, + totalBytes: 400, + count: 0, + totalCount: 400, + children: [ + { + name: "objects", + bytes: 0, + totalBytes: 200, + count: 0, + totalCount: 200, + children: [makeTestCensusNode(), makeTestCensusNode()], + }, + { + name: "other", + bytes: 0, + totalBytes: 200, + count: 0, + totalCount: 200, + children: [makeTestCensusNode(), makeTestCensusNode()], + }, + ], + }, + }), +}); + +var TEST_SNAPSHOT_LIST_ITEM_PROPS = Object.freeze({ + onClick: noop, + onSave: noop, + onDelete: noop, + item: TEST_SNAPSHOT, + index: 1234, +}); + +function onNextAnimationFrame(fn) { + return () => requestAnimationFrame(() => requestAnimationFrame(fn)); +} + +/** + * Render the provided ReactElement in the provided HTML container. + * Returns a Promise that will resolve the rendered element as a React + * component. + */ +function renderComponent(element, container) { + return new Promise(resolve => { + const component = ReactDOM.render( + element, + container, + onNextAnimationFrame(() => { + dumpn("Rendered = " + container.innerHTML); + resolve(component); + }) + ); + }); +} + +function dumpn(msg) { + dump(`MEMORY-TEST: ${msg}\n`); +} diff --git a/devtools/client/memory/test/chrome/test_CensusTreeItem_01.html b/devtools/client/memory/test/chrome/test_CensusTreeItem_01.html new file mode 100644 index 0000000000..21d900b668 --- /dev/null +++ b/devtools/client/memory/test/chrome/test_CensusTreeItem_01.html @@ -0,0 +1,65 @@ +<!DOCTYPE HTML> +<html> +<!-- +Test that children pointers show up at the correct times. +--> +<head> + <meta charset="utf-8"> + <title>Tree component test</title> + <script 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> + <!-- Give the container height so that the whole tree is rendered. --> + <div id="container" style="height: 900px;"></div> + + <pre id="test"> + <script src="head.js" type="application/javascript"></script> + <script type="application/javascript"> + "use strict"; + window.onload = async function() { + try { + const container = document.getElementById("container"); + + await renderComponent(CensusTreeItem(immutableUpdate(TEST_CENSUS_TREE_ITEM_PROPS, { + inverted: true, + depth: 0, + })), container); + + ok(!container.querySelector(".children-pointer"), + "Don't show children pointer for roots when we are inverted"); + + await renderComponent(CensusTreeItem(immutableUpdate(TEST_CENSUS_TREE_ITEM_PROPS, { + inverted: true, + depth: 1, + })), container); + + ok(container.querySelector(".children-pointer"), + "Do show children pointer for non-roots when we are inverted"); + + await renderComponent(CensusTreeItem(immutableUpdate(TEST_CENSUS_TREE_ITEM_PROPS, { + inverted: false, + item: immutableUpdate(TEST_CENSUS_TREE_ITEM_PROPS.item, { children: undefined }), + })), container); + + ok(!container.querySelector(".children-pointer"), + "Don't show children pointer when non-inverted and no children"); + + await renderComponent(CensusTreeItem(immutableUpdate(TEST_CENSUS_TREE_ITEM_PROPS, { + inverted: false, + depth: 0, + item: immutableUpdate(TEST_CENSUS_TREE_ITEM_PROPS.item, { children: [{}] }), + })), container); + + ok(container.querySelector(".children-pointer"), + "Do show children pointer when non-inverted and have children"); + } catch (e) { + ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e)); + } finally { + SimpleTest.finish(); + } + }; + </script> + </pre> +</body> +</html> diff --git a/devtools/client/memory/test/chrome/test_DominatorTreeItem_01.html b/devtools/client/memory/test/chrome/test_DominatorTreeItem_01.html new file mode 100644 index 0000000000..c8cb6b6036 --- /dev/null +++ b/devtools/client/memory/test/chrome/test_DominatorTreeItem_01.html @@ -0,0 +1,46 @@ +<!DOCTYPE HTML> +<html> +<!-- +Test that we don't display `JS::ubi::RootList` for the root, and instead show "GC Roots". +--> +<head> + <meta charset="utf-8"> + <title>Tree component test</title> + <script 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> + <!-- Give the container height so that the whole tree is rendered. --> + <div id="container" style="height: 900px;"></div> + + <pre id="test"> + <script src="head.js" type="application/javascript"></script> + <script type="application/javascript"> + "use strict"; + window.onload = async function() { + try { + const container = document.getElementById("container"); + + await renderComponent(DominatorTreeItem({ + item: makeTestDominatorTreeNode({ label: ["other", "JS::ubi::RootList"] }), + depth: 0, + arrow: dom.div(), + focused: true, + getPercentSize: _ => 50, + onViewSourceInDebugger: _ => { }, + }), container); + + ok(!container.textContent.includes("JS::ubi::RootList"), + "Should not display `JS::ubi::RootList`"); + ok(container.textContent.includes("GC Roots"), + "Should display `GC Roots` instead"); + } catch (e) { + ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e)); + } finally { + SimpleTest.finish(); + } + }; + </script> + </pre> +</body> +</html> diff --git a/devtools/client/memory/test/chrome/test_DominatorTree_01.html b/devtools/client/memory/test/chrome/test_DominatorTree_01.html new file mode 100644 index 0000000000..0067a0f412 --- /dev/null +++ b/devtools/client/memory/test/chrome/test_DominatorTree_01.html @@ -0,0 +1,52 @@ +<!DOCTYPE HTML> +<html> +<!-- +Test that we show a place holder for a subtree we are lazily fetching. +--> +<head> + <meta charset="utf-8"> + <title>Tree component test</title> + <script 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> + <!-- Give the container height so that the whole tree is rendered. --> + <div id="container" style="height: 900px;"></div> + + <pre id="test"> + <script src="head.js" type="application/javascript"></script> + <script type="application/javascript"> + "use strict"; + window.onload = async function() { + try { + const container = document.getElementById("container"); + + const root = makeTestDominatorTreeNode({ moreChildrenAvailable: true}); + ok(!root.children); + + const expanded = new Set(); + expanded.add(root.nodeId); + + await renderComponent(DominatorTreeComponent(immutableUpdate( + TEST_DOMINATOR_TREE_PROPS, { + dominatorTree: immutableUpdate(TEST_DOMINATOR_TREE_PROPS.dominatorTree, { + expanded, + root, + state: dominatorTreeState.INCREMENTAL_FETCHING, + activeFetchRequestCount: 1, + }), + })), container); + + ok(container.querySelector(".subtree-fetching"), + "Expanded nodes with more children available, but no children " + + "loaded, should get a placeholder"); + } catch (e) { + ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e)); + } finally { + SimpleTest.finish(); + } + }; + </script> + </pre> +</body> +</html> diff --git a/devtools/client/memory/test/chrome/test_DominatorTree_02.html b/devtools/client/memory/test/chrome/test_DominatorTree_02.html new file mode 100644 index 0000000000..66aad95296 --- /dev/null +++ b/devtools/client/memory/test/chrome/test_DominatorTree_02.html @@ -0,0 +1,52 @@ +<!DOCTYPE HTML> +<html> +<!-- +Test that we show a link to load more children when some (but not all) are loaded. +--> +<head> + <meta charset="utf-8"> + <title>Tree component test</title> + <script 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> + <!-- Give the container height so that the whole tree is rendered. --> + <div id="container" style="height: 900px;"></div> + + <pre id="test"> + <script src="head.js" type="application/javascript"></script> + <script type="application/javascript"> + "use strict"; + window.onload = async function() { + try { + const container = document.getElementById("container"); + + const root = makeTestDominatorTreeNode({ moreChildrenAvailable: true }, [ + makeTestDominatorTreeNode({}), + ]); + ok(root.children); + ok(root.moreChildrenAvailable); + + const expanded = new Set(); + expanded.add(root.nodeId); + + await renderComponent(DominatorTreeComponent(immutableUpdate( + TEST_DOMINATOR_TREE_PROPS, { + dominatorTree: immutableUpdate(TEST_DOMINATOR_TREE_PROPS.dominatorTree, { + expanded, + root, + }), + })), container); + + ok(container.querySelector(".more-children"), + "Should get a link to load more children"); + } catch (e) { + ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e)); + } finally { + SimpleTest.finish(); + } + }; + </script> + </pre> +</body> +</html> diff --git a/devtools/client/memory/test/chrome/test_DominatorTree_03.html b/devtools/client/memory/test/chrome/test_DominatorTree_03.html new file mode 100644 index 0000000000..6fcfa3d577 --- /dev/null +++ b/devtools/client/memory/test/chrome/test_DominatorTree_03.html @@ -0,0 +1,77 @@ +<!DOCTYPE HTML> +<html> +<!-- +Test that expanded DominatorTreeItems are correctly rendered and updated +--> +<head> + <meta charset="utf-8"> + <title>Tree component test</title> + <script 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> + <!-- Give the container height so that the whole tree is rendered. --> + <div id="container" style="height: 900px;"></div> + + <pre id="test"> + <script src="head.js" type="application/javascript"></script> + <script type="application/javascript"> + "use strict"; + window.onload = async function() { + try { + const container = document.getElementById("container"); + + // simple tree with one root and one child + const root = makeTestDominatorTreeNode( + { moreChildrenAvailable: false }, + [ + makeTestDominatorTreeNode({ moreChildrenAvailable: false }), + ]); + ok(root.children); + + // root node is expanded + const expanded = new Set(); + expanded.add(root.nodeId); + + await renderComponent( + DominatorTreeComponent(immutableUpdate( + TEST_DOMINATOR_TREE_PROPS, + { + dominatorTree: immutableUpdate( + TEST_DOMINATOR_TREE_PROPS.dominatorTree, + { expanded, root } + ), + })), container); + ok(true, "Dominator tree rendered"); + + is(container.querySelectorAll(".tree-node").length, 2, + "Should display two rows"); + is(container.querySelectorAll(".arrow.open").length, 1, + "Should display one expanded arrow"); + + await renderComponent( + DominatorTreeComponent(immutableUpdate( + TEST_DOMINATOR_TREE_PROPS, + { + dominatorTree: immutableUpdate( + TEST_DOMINATOR_TREE_PROPS.dominatorTree, + { expanded: new Set(), root } + ), + })), container); + + ok(true, "Dominator tree props updated to collapse all nodes"); + + is(container.querySelectorAll(".tree-node").length, 1, + "Should display only one row"); + is(container.querySelectorAll(".arrow.open").length, 0, + "Should display no expanded arrow"); + } catch (e) { + ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e)); + } finally { + SimpleTest.finish(); + } + }; + </script> + </pre> +</body> +</html> diff --git a/devtools/client/memory/test/chrome/test_Heap_01.html b/devtools/client/memory/test/chrome/test_Heap_01.html new file mode 100644 index 0000000000..2facc3d221 --- /dev/null +++ b/devtools/client/memory/test/chrome/test_Heap_01.html @@ -0,0 +1,51 @@ +<!DOCTYPE HTML> +<html> +<!-- +Test that rendering a dominator tree error is handled correctly. +--> +<head> + <meta charset="utf-8"> + <title>Tree component test</title> + <script 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> + <div id="container"></div> + <pre id="test"> + <script src="head.js" type="application/javascript"></script> + + <script type="application/javascript"> + "use strict"; + window.onload = async function() { + try { + ok(React, "Should get React"); + ok(Heap, "Should get Heap"); + + const errorMessage = "Something went wrong!"; + const container = document.getElementById("container"); + + const props = immutableUpdate(TEST_HEAP_PROPS, { + view: { state: viewState.DOMINATOR_TREE }, + snapshot: immutableUpdate(TEST_HEAP_PROPS.snapshot, { + dominatorTree: { + error: new Error(errorMessage), + state: dominatorTreeState.ERROR, + }, + }), + }); + + await renderComponent(Heap(props), container); + + ok(container.querySelector(".error"), "Should render an error view"); + ok(container.textContent.includes(errorMessage), + "Should see our error message"); + } catch (e) { + ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e)); + } finally { + SimpleTest.finish(); + } + }; + </script> + </pre> +</body> +</html> diff --git a/devtools/client/memory/test/chrome/test_Heap_02.html b/devtools/client/memory/test/chrome/test_Heap_02.html new file mode 100644 index 0000000000..343ee66714 --- /dev/null +++ b/devtools/client/memory/test/chrome/test_Heap_02.html @@ -0,0 +1,78 @@ +<!DOCTYPE HTML> +<html> +<!-- +Test that the currently selected view is rendered. +--> +<head> + <meta charset="utf-8"> + <title>Tree component test</title> + <script 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> + <div id="container"></div> + <pre id="test"> + <script src="head.js" type="application/javascript"></script> + <script type="application/javascript"> + "use strict"; + window.onload = async function() { + try { + ok(React, "Should get React"); + ok(Heap, "Should get Heap"); + + const container = document.getElementById("container"); + + // Dominator tree view. + + await renderComponent(Heap(immutableUpdate(TEST_HEAP_PROPS, { + view: { state: viewState.DOMINATOR_TREE }, + })), container); + + ok(container.querySelector(`[data-state=${dominatorTreeState.LOADED}]`), + "Should render the dominator tree."); + + // Census view. + + await renderComponent(Heap(immutableUpdate(TEST_HEAP_PROPS, { + view: { state: viewState.CENSUS }, + })), container); + + ok(container.querySelector(`[data-state=${censusState.SAVED}]`), + "Should render the census."); + + // Diffing view. + + await renderComponent(Heap(immutableUpdate(TEST_HEAP_PROPS, { + view: { state: viewState.DIFFING }, + snapshot: null, + diffing: { + firstSnapshotId: null, + secondSnapshotId: null, + census: null, + error: null, + state: diffingState.SELECTING, + }, + })), container); + + ok(container.querySelector(`[data-state=${diffingState.SELECTING}]`), + "Should render the diffing."); + + // Initial view. + + await renderComponent(Heap(immutableUpdate(TEST_HEAP_PROPS, { + snapshot: null, + diffing: null, + })), container); + + ok(container.querySelector("[data-state=initial]"), + "With no snapshot, nor a diffing, should render initial prompt."); + } catch (e) { + ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e)); + } finally { + SimpleTest.finish(); + } + }; + </script> + </pre> +</body> +</html> diff --git a/devtools/client/memory/test/chrome/test_Heap_03.html b/devtools/client/memory/test/chrome/test_Heap_03.html new file mode 100644 index 0000000000..69f95f4275 --- /dev/null +++ b/devtools/client/memory/test/chrome/test_Heap_03.html @@ -0,0 +1,79 @@ +<!DOCTYPE HTML> +<html> +<!-- +Test that we show a throbber while computing and fetching dominator trees, +but not in other dominator tree states. +--> +<head> + <meta charset="utf-8"> + <title>Tree component test</title> + <script 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> + <div id="container"></div> + <pre id="test"> + <script src="head.js" type="application/javascript"></script> + <script type="application/javascript"> + "use strict"; + window.onload = async function() { + try { + const container = document.getElementById("container"); + + for (const state of [dominatorTreeState.COMPUTING, dominatorTreeState.FETCHING]) { + await renderComponent(Heap(immutableUpdate(TEST_HEAP_PROPS, { + view: { state: viewState.DOMINATOR_TREE }, + snapshot: immutableUpdate(TEST_HEAP_PROPS.snapshot, { + dominatorTree: immutableUpdate(TEST_HEAP_PROPS.snapshot.dominatorTree, { + state, + root: null, + dominatorTreeId: state === dominatorTreeState.FETCHING ? 1 : null, + }), + }), + })), container); + + ok(container.querySelector(".devtools-throbber"), + `Should show a throbber for state = ${state}`); + } + + for ( + const state of [ + dominatorTreeState.LOADED, dominatorTreeState.INCREMENTAL_FETCHING, + ]) { + await renderComponent(Heap(immutableUpdate(TEST_HEAP_PROPS, { + view: { state: viewState.DOMINATOR_TREE }, + snapshot: immutableUpdate(TEST_HEAP_PROPS.snapshot, { + dominatorTree: immutableUpdate(TEST_HEAP_PROPS.snapshot.dominatorTree, { + state, + activeFetchRequestCount: + state === dominatorTreeState.INCREMENTAL_FETCHING ? 1 : undefined, + }), + }), + })), container); + + ok(!container.querySelector(".devtools-throbber"), + `Should not show a throbber for state = ${state}`); + } + + await renderComponent(Heap(immutableUpdate(TEST_HEAP_PROPS, { + view: { state: viewState.DOMINATOR_TREE }, + snapshot: immutableUpdate(TEST_HEAP_PROPS.snapshot, { + dominatorTree: { + state: dominatorTreeState.ERROR, + error: new Error("example error for testing"), + }, + }), + })), container); + + ok(!container.querySelector(".devtools-throbber"), + `Should not show a throbber for ERROR state`); + } catch (e) { + ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e)); + } finally { + SimpleTest.finish(); + } + }; + </script> + </pre> +</body> +</html> diff --git a/devtools/client/memory/test/chrome/test_Heap_04.html b/devtools/client/memory/test/chrome/test_Heap_04.html new file mode 100644 index 0000000000..76de5e4826 --- /dev/null +++ b/devtools/client/memory/test/chrome/test_Heap_04.html @@ -0,0 +1,122 @@ +<!DOCTYPE HTML> +<html> +<!-- +Test that we show the "hey you're not recording allocation stacks" message at the appropriate times. +--> +<head> + <meta charset="utf-8"> + <title>Tree component test</title> + <script 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> + <div id="container"></div> + <pre id="test"> + <script src="head.js" type="application/javascript"></script> + <script type="application/javascript"> + "use strict"; + window.onload = async function() { + try { + const container = document.getElementById("container"); + + await renderComponent(Heap(immutableUpdate(TEST_HEAP_PROPS, { + snapshot: immutableUpdate(TEST_HEAP_PROPS.snapshot, { + census: immutableUpdate(TEST_HEAP_PROPS.snapshot.census, { + report: { + bytes: 1, + totalBytes: 1, + count: 1, + totalCount: 1, + id: 1, + parent: undefined, + children: [ + { + name: "noStack", + bytes: 1, + totalBytes: 1, + count: 1, + totalCount: 1, + children: undefined, + id: 3, + parent: 1, + }, + ], + }, + display: censusDisplays.allocationStack, + }), + }), + })), container); + + ok(container.querySelector(".no-allocation-stacks"), + "When there are no allocation stacks, we should show the message"); + + await renderComponent(Heap(immutableUpdate(TEST_HEAP_PROPS, { + snapshot: immutableUpdate(TEST_HEAP_PROPS.snapshot, { + census: immutableUpdate(TEST_HEAP_PROPS.snapshot.census, { + report: { + bytes: 1, + totalBytes: 1, + count: 1, + totalCount: 1, + id: 1, + parent: undefined, + children: [ + { + name: Cu.getJSTestingFunctions().saveStack(), + bytes: 1, + totalBytes: 1, + count: 1, + totalCount: 1, + children: undefined, + id: 2, + parent: 1, + }, + { + name: "noStack", + bytes: 1, + totalBytes: 1, + count: 1, + totalCount: 1, + children: undefined, + id: 3, + parent: 1, + }, + ], + }, + display: censusDisplays.allocationStack, + }), + }), + })), container); + + ok(!container.querySelector(".no-allocation-stacks"), + "When there are allocation stacks, we should not show the message"); + + await renderComponent(Heap(immutableUpdate(TEST_HEAP_PROPS, { + snapshot: immutableUpdate(TEST_HEAP_PROPS.snapshot, { + census: immutableUpdate(TEST_HEAP_PROPS.snapshot.census, { + report: { + bytes: 1, + totalBytes: 1, + count: 1, + totalCount: 1, + id: 1, + parent: undefined, + children: undefined, + }, + display: censusDisplays.allocationStack, + }), + }), + })), container); + + ok(!container.querySelector(".no-allocation-stacks"), + "When there isn't census data, we should not show the message"); + } catch (e) { + ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e)); + } finally { + SimpleTest.finish(); + } + }; + </script> + </pre> +</body> +</html> diff --git a/devtools/client/memory/test/chrome/test_Heap_05.html b/devtools/client/memory/test/chrome/test_Heap_05.html new file mode 100644 index 0000000000..bd3fc393cc --- /dev/null +++ b/devtools/client/memory/test/chrome/test_Heap_05.html @@ -0,0 +1,133 @@ +<!DOCTYPE HTML> +<html> +<!-- +Test that we show a message when the census results are empty. +--> +<head> + <meta charset="utf-8"> + <title>Tree component test</title> + <script 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> + <div id="container"></div> + <pre id="test"> + <script src="head.js" type="application/javascript"></script> + <script type="application/javascript"> + "use strict"; + window.onload = async function() { + try { + const container = document.getElementById("container"); + + await renderComponent(Heap(immutableUpdate(TEST_HEAP_PROPS, { + snapshot: immutableUpdate(TEST_HEAP_PROPS.snapshot, { + census: immutableUpdate(TEST_HEAP_PROPS.snapshot.census, { + report: { + bytes: 1, + totalBytes: 1, + count: 1, + totalCount: 1, + id: 1, + parent: undefined, + children: [ + { + name: Cu.getJSTestingFunctions().saveStack(), + bytes: 1, + totalBytes: 1, + count: 1, + totalCount: 1, + children: undefined, + id: 2, + parent: 1, + }, + { + name: "noStack", + bytes: 1, + totalBytes: 1, + count: 1, + totalCount: 1, + children: undefined, + id: 3, + parent: 1, + }, + ], + }, + display: censusDisplays.allocationStack, + }), + }), + })), container); + + ok(!container.querySelector(".empty"), + "When the report is not empty, we should not show the empty message"); + + // Empty Census Report + + const emptyCensus = { + report: { + bytes: 0, + totalBytes: 0, + count: 0, + totalCount: 0, + id: 1, + parent: undefined, + children: undefined, + }, + parentMap: Object.create(null), + display: censusDisplays.allocationStack, + filter: null, + expanded: new Immutable.Set(), + focused: null, + state: censusState.SAVED, + }; + + await renderComponent(Heap(immutableUpdate(TEST_HEAP_PROPS, { + snapshot: immutableUpdate(TEST_HEAP_PROPS.snapshot, { + census: immutableUpdate(TEST_HEAP_PROPS.snapshot.census, emptyCensus), + }), + })), container); + + ok(container.querySelector(".empty"), + "When the report is empty in census view, we show the empty message"); + ok(container.textContent.includes(L10N.getStr("heapview.empty"))); + + // Empty Diffing Report + + await renderComponent(Heap(immutableUpdate(TEST_HEAP_PROPS, { + view: { state: viewState.DIFFING }, + diffing: { + firstSnapshotId: 1, + secondSnapshotId: 2, + census: emptyCensus, + state: diffingState.TOOK_DIFF, + }, + snapshot: null, + })), container); + + ok(container.querySelector(".empty"), + "When the report is empty in diffing view, the empty message is shown"); + ok(container.textContent.includes(L10N.getStr("heapview.no-difference"))); + + // Empty Filtered Census + + await renderComponent(Heap(immutableUpdate(TEST_HEAP_PROPS, { + snapshot: immutableUpdate(TEST_HEAP_PROPS.snapshot, { + census: immutableUpdate( + TEST_HEAP_PROPS.snapshot.census, immutableUpdate(emptyCensus, { + filter: "zzzz", + })), + }), + })), container); + + ok(container.querySelector(".empty"), + "When the report is empty in census view w/ filter, we show the empty message"); + ok(container.textContent.includes(L10N.getStr("heapview.none-match"))); + } catch (e) { + ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e)); + } finally { + SimpleTest.finish(); + } + }; + </script> + </pre> +</body> +</html> diff --git a/devtools/client/memory/test/chrome/test_List_01.html b/devtools/client/memory/test/chrome/test_List_01.html new file mode 100644 index 0000000000..4ffab49620 --- /dev/null +++ b/devtools/client/memory/test/chrome/test_List_01.html @@ -0,0 +1,73 @@ +<!DOCTYPE HTML> +<html> +<!-- +Test to verify the delete button calls the onDelete handler for an item +--> +<head> + <meta charset="utf-8"> + <title>Tree component test</title> + <script 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> + <div id="container"></div> + + <pre id="test"> + <script src="head.js" type="application/javascript"></script> + <script type="application/javascript"> + "use strict"; + window.onload = async function() { + try { + const container = document.getElementById("container"); + + const deletedSnapshots = []; + + const snapshots = [ TEST_SNAPSHOT, TEST_SNAPSHOT, TEST_SNAPSHOT ] + .map((snapshot, index) => immutableUpdate(snapshot, { + index: snapshot.index + index, + })); + + await renderComponent( + List({ + itemComponent: SnapshotListItem, + onClick: noop, + onDelete: (item) => deletedSnapshots.push(item), + items: snapshots, + }), + container + ); + + const deleteButtons = container.querySelectorAll(".delete"); + + is(container.querySelectorAll(".snapshot-list-item").length, 3, + "There are 3 list items\n"); + is(deletedSnapshots.length, 0, + "Not snapshots have been deleted\n"); + + deleteButtons[1].click(); + + is(deletedSnapshots.length, 1, "One snapshot was deleted\n"); + is(deletedSnapshots[0], snapshots[1], + "Deleted snapshot was added to the deleted list\n"); + + deleteButtons[0].click(); + + is(deletedSnapshots.length, 2, "Two snapshots were deleted\n"); + is(deletedSnapshots[1], snapshots[0], + "Deleted snapshot was added to the deleted list\n"); + + deleteButtons[2].click(); + + is(deletedSnapshots.length, 3, "Three snapshots were deleted\n"); + is(deletedSnapshots[2], snapshots[2], + "Deleted snapshot was added to the deleted list\n"); + } catch (e) { + ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e)); + } finally { + SimpleTest.finish(); + } + }; + </script> + </pre> +</body> +</html> diff --git a/devtools/client/memory/test/chrome/test_ShortestPaths_01.html b/devtools/client/memory/test/chrome/test_ShortestPaths_01.html new file mode 100644 index 0000000000..29905bfaca --- /dev/null +++ b/devtools/client/memory/test/chrome/test_ShortestPaths_01.html @@ -0,0 +1,112 @@ +<!DOCTYPE HTML> +<html> +<!-- +Test that the ShortestPaths component properly renders a graph of the merged shortest paths. +--> +<head> + <meta charset="utf-8"> + <title>Tree component test</title> + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"> + + <script type="application/javascript" + src="chrome://global/content/third_party/d3/d3.js"> + </script> + <script type="application/javascript" + src="chrome://devtools/content/shared/vendor/dagre-d3.js"> + </script> +</head> +<body> + <!-- Give the container height so that the whole tree is rendered. --> + <div id="container" style="height: 900px;"></div> + + <pre id="test"> + <script src="head.js" type="application/javascript"></script> + <script type="application/javascript"> + "use strict"; + window.onload = async function() { + try { + const container = document.getElementById("container"); + + await renderComponent(ShortestPaths(TEST_SHORTEST_PATHS_PROPS), container); + + let found1 = false; + let found2 = false; + let found3 = false; + + let found1to2 = false; + let found1to3 = false; + let found2to3 = false; + + const tspans = [...container.querySelectorAll("tspan")]; + for (const el of tspans) { + const text = el.textContent.trim(); + dumpn("tspan's text = " + text); + + switch (text) { + // Nodes + + case "other › SomeType @ 0x1": { + ok(!found1, "Should only find node 1 once"); + found1 = true; + break; + } + + case "other › SomeType @ 0x2": { + ok(!found2, "Should only find node 2 once"); + found2 = true; + break; + } + + case "other › SomeType @ 0x3": { + ok(!found3, "Should only find node 3 once"); + found3 = true; + break; + } + + // Edges + + case "1->2": { + ok(!found1to2, "Should only find edge 1->2 once"); + found1to2 = true; + break; + } + + case "1->3": { + ok(!found1to3, "Should only find edge 1->3 once"); + found1to3 = true; + break; + } + + case "2->3": { + ok(!found2to3, "Should only find edge 2->3 once"); + found2to3 = true; + break; + } + + // Unexpected + + default: { + ok(false, `Unexpected tspan: ${text}`); + break; + } + } + } + + ok(found1, "Should have rendered node 1"); + ok(found2, "Should have rendered node 2"); + ok(found3, "Should have rendered node 3"); + + ok(found1to2, "Should have rendered edge 1->2"); + ok(found1to3, "Should have rendered edge 1->3"); + ok(found2to3, "Should have rendered edge 2->3"); + } catch (e) { + ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e)); + } finally { + SimpleTest.finish(); + } + }; + </script> + </pre> +</body> +</html> diff --git a/devtools/client/memory/test/chrome/test_ShortestPaths_02.html b/devtools/client/memory/test/chrome/test_ShortestPaths_02.html new file mode 100644 index 0000000000..cbf0370d22 --- /dev/null +++ b/devtools/client/memory/test/chrome/test_ShortestPaths_02.html @@ -0,0 +1,46 @@ +<!DOCTYPE HTML> +<html> +<!-- +Test that the ShortestPaths component renders a suggestion to select a node when there is no graph. +--> +<head> + <meta charset="utf-8"> + <title>Tree component test</title> + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"> + + <script type="application/javascript" + src="chrome://global/content/third_party/d3/d3.js"> + </script> + <script type="application/javascript" + src="chrome://devtools/content/shared/vendor/dagre-d3.js"> + </script> +</head> +<body> + <!-- Give the container height so that the whole tree is rendered. --> + <div id="container" style="height: 900px;"></div> + + <pre id="test"> + <script src="head.js" type="application/javascript"></script> + <script type="application/javascript"> + "use strict"; + window.onload = async function() { + try { + const container = document.getElementById("container"); + + await renderComponent(ShortestPaths(immutableUpdate(TEST_SHORTEST_PATHS_PROPS, + { graph: null })), + container); + + ok(container.textContent.includes(L10N.getStr("shortest-paths.select-node")), + "The node selection prompt is displayed"); + } catch (e) { + ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e)); + } finally { + SimpleTest.finish(); + } + }; + </script> + </pre> +</body> +</html> diff --git a/devtools/client/memory/test/chrome/test_SnapshotListItem_01.html b/devtools/client/memory/test/chrome/test_SnapshotListItem_01.html new file mode 100644 index 0000000000..20fc137479 --- /dev/null +++ b/devtools/client/memory/test/chrome/test_SnapshotListItem_01.html @@ -0,0 +1,53 @@ +<!DOCTYPE HTML> +<html> +<!-- +Test to verify that the delete button only shows up for a snapshot when it has a +path. +--> +<head> + <meta charset="utf-8"> + <title>Tree component test</title> + <script 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> + <div id="container"></div> + + <pre id="test"> + <script src="head.js" type="application/javascript"></script> + <script type="application/javascript"> + "use strict"; + window.onload = async function() { + try { + const container = document.getElementById("container"); + + await renderComponent( + SnapshotListItem(TEST_SNAPSHOT_LIST_ITEM_PROPS), + container + ); + + ok(container.querySelector(".delete"), + "Should have delete button when there is a path"); + + const pathlessProps = immutableUpdate( + TEST_SNAPSHOT_LIST_ITEM_PROPS, + {item: immutableUpdate(TEST_SNAPSHOT, {path: null})} + ); + + await renderComponent( + SnapshotListItem(pathlessProps), + container + ); + + ok(!container.querySelector(".delete"), + "No delete button should be found if there is no path\n"); + } catch (e) { + ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e)); + } finally { + SimpleTest.finish(); + } + }; + </script> + </pre> +</body> +</html> diff --git a/devtools/client/memory/test/chrome/test_Toolbar_01.html b/devtools/client/memory/test/chrome/test_Toolbar_01.html new file mode 100644 index 0000000000..3bf934c77c --- /dev/null +++ b/devtools/client/memory/test/chrome/test_Toolbar_01.html @@ -0,0 +1,48 @@ +<!DOCTYPE HTML> +<html> +<!-- +Test that the Toolbar component shows the view switcher only at the appropriate times. +--> +<head> + <meta charset="utf-8"> + <title>Tree component test</title> + <script 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> + <div id="container"></div> + <pre id="test"> + <script src="head.js" type="application/javascript"></script> + <script type="application/javascript"> + "use strict"; + window.onload = async function() { + try { + const container = document.getElementById("container"); + + // Census and dominator tree views. + + for (const view of [viewState.CENSUS, viewState.DOMINATOR_TREE]) { + await renderComponent(Toolbar(immutableUpdate(TEST_TOOLBAR_PROPS, { + view: { state: view }, + })), container); + + ok(container.querySelector("#select-view"), + `The view selector is shown in view = ${view}`); + } + + await renderComponent(Toolbar(immutableUpdate(TEST_TOOLBAR_PROPS, { + view: { state: viewState.DIFFING }, + })), container); + + ok(!container.querySelector("#select-view"), + "The view selector is NOT shown in the DIFFING view"); + } catch (e) { + ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e)); + } finally { + SimpleTest.finish(); + } + }; + </script> + </pre> +</body> +</html> diff --git a/devtools/client/memory/test/chrome/test_TreeMap_01.html b/devtools/client/memory/test/chrome/test_TreeMap_01.html new file mode 100644 index 0000000000..7b8b98b9a7 --- /dev/null +++ b/devtools/client/memory/test/chrome/test_TreeMap_01.html @@ -0,0 +1,44 @@ +<!DOCTYPE HTML> +<html> +<!-- +Test that the Tree Map correctly renders onto 2 managed canvases. +--> +<head> + <meta charset="utf-8"> + <title>Tree component test</title> + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"> + + <script type="application/javascript" + src="chrome://global/content/third_party/d3/d3.js"> + </script> +</head> +<body> + <!-- Give the container height so that the whole tree is rendered. --> + <div id="container" style="height: 900px;"></div> + + <pre id="test"> + <script src="head.js" type="application/javascript"></script> + <script type="application/javascript"> + "use strict"; + window.onload = async function() { + try { + const container = document.getElementById("container"); + + await renderComponent(TreeMap(TEST_TREE_MAP_PROPS), container); + + const treeMapContainer = container.querySelector(".tree-map-container"); + ok(treeMapContainer, "Component creates a container"); + + const canvases = treeMapContainer.querySelectorAll("canvas"); + is(canvases.length, 2, "Creates 2 canvases"); + } catch (e) { + ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e)); + } finally { + SimpleTest.finish(); + } + }; + </script> + </pre> +</body> +</html> |