Migrate devtools-active-dom-objects heap layout test
Bug: 1110817
Change-Id: I38bb4d748f5f70388b7b0808090498929462928a
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2406156
Commit-Queue: Jack Franklin <jacktfranklin@chromium.org>
Reviewed-by: Sigurd Schneider <sigurds@chromium.org>
diff --git a/test/e2e/helpers/memory-helpers.ts b/test/e2e/helpers/memory-helpers.ts
index 4dbd4a9..11f9859 100644
--- a/test/e2e/helpers/memory-helpers.ts
+++ b/test/e2e/helpers/memory-helpers.ts
@@ -5,7 +5,7 @@
import {assert} from 'chai';
import * as puppeteer from 'puppeteer';
-import {platform} from '../../shared/helper.js';
+import {$, platform, waitForElementWithTextContent} from '../../shared/helper.js';
import {$$, click, getBrowserAndPages, pasteText, waitFor, waitForFunction, waitForNone} from '../../shared/helper.js';
@@ -174,3 +174,15 @@
export async function waitForRetainerChain(expectedRetainers: Array<string>) {
await waitForFunction(assertRetainerChain.bind(null, expectedRetainers));
}
+
+export async function changeViewViaDropdown(newPerspective: string) {
+ const perspectiveDropdownSelector = 'select[aria-label="Perspective"]';
+ const dropdown = await $(perspectiveDropdownSelector) as puppeteer.ElementHandle<HTMLSelectElement>;
+
+ const optionToSelect = await waitForElementWithTextContent(newPerspective, dropdown);
+ const optionValue = await optionToSelect.evaluate(opt => opt.getAttribute('value'));
+ if (!optionValue) {
+ throw new Error(`Could not find heap snapshot perspective option: ${newPerspective}`);
+ }
+ dropdown.select(optionValue);
+}
diff --git a/test/e2e/memory/memory_test.ts b/test/e2e/memory/memory_test.ts
index 94c437b..74442bc 100644
--- a/test/e2e/memory/memory_test.ts
+++ b/test/e2e/memory/memory_test.ts
@@ -3,10 +3,9 @@
// found in the LICENSE file.
import {assert} from 'chai';
-
-import {$$, goToResource} from '../../shared/helper.js';
+import {$$, click, getBrowserAndPages, goToResource, waitForElementsWithTextContent, waitForElementWithTextContent, waitForFunction} from '../../shared/helper.js';
import {describe, it} from '../../shared/mocha-extensions.js';
-import {findSearchResult, navigateToMemoryTab, setSearchFilter, takeHeapSnapshot, waitForNonEmptyHeapSnapshotData, waitForRetainerChain, waitForSearchResultNumber} from '../helpers/memory-helpers.js';
+import {changeViewViaDropdown, findSearchResult, navigateToMemoryTab, setSearchFilter, takeHeapSnapshot, waitForNonEmptyHeapSnapshotData, waitForRetainerChain, waitForSearchResultNumber} from '../helpers/memory-helpers.js';
describe('The Memory Panel', async () => {
it('Loads content', async () => {
@@ -69,4 +68,23 @@
'Window /',
]);
});
+
+ it('Puts all ActiveDOMObjects with pending activities into one group', async () => {
+ await goToResource('memory/dom-objects.html');
+ await navigateToMemoryTab();
+ await takeHeapSnapshot();
+ await waitForNonEmptyHeapSnapshotData();
+ await changeViewViaDropdown('Containment');
+ const pendingActiviesElement = await waitForElementWithTextContent('Pending activities');
+
+ // Focus and then expand the pending activities row to show its children
+ await click(pendingActiviesElement);
+ const {frontend} = getBrowserAndPages();
+ await frontend.keyboard.press('ArrowRight');
+
+ await waitForFunction(async () => {
+ const pendingActiviesChildren = await waitForElementsWithTextContent('MediaQueryList');
+ return pendingActiviesChildren.length === 2;
+ });
+ });
});
diff --git a/test/e2e/resources/memory/BUILD.gn b/test/e2e/resources/memory/BUILD.gn
index adef41d..969e46d 100644
--- a/test/e2e/resources/memory/BUILD.gn
+++ b/test/e2e/resources/memory/BUILD.gn
@@ -8,6 +8,7 @@
sources = [
"default.html",
"detached-node.html",
+ "dom-objects.html",
"event-listeners.html",
]
}
diff --git a/test/e2e/resources/memory/dom-objects.html b/test/e2e/resources/memory/dom-objects.html
new file mode 100644
index 0000000..d8245d9
--- /dev/null
+++ b/test/e2e/resources/memory/dom-objects.html
@@ -0,0 +1,16 @@
+<!--
+ Copyright 2020 The Chromium Authors. All rights reserved.
+ Use of this source code is governed by a BSD-style license that can be
+ found in the LICENSE file.
+-->
+<h1>Memory Panel (Heap profiler) Test</h1>
+<script>
+ function onChange(e) {
+ console.log('onChange ' + e.matches);
+ }
+ var m = window.matchMedia('(min-width: 1400px)');
+ m.addListener(onChange);
+ m = window.matchMedia('(min-height: 1800px)');
+ m.addListener(onChange);
+ console.log('Created 2 MediaQueryList elements');
+</script>
diff --git a/test/shared/helper.ts b/test/shared/helper.ts
index 43f6f60..5a8f11e 100644
--- a/test/shared/helper.ts
+++ b/test/shared/helper.ts
@@ -177,6 +177,19 @@
return element;
};
+/**
+ * Search for all elements based on their textContent
+ *
+ * @param textContent The text content to search for.
+ * @param root The root of the search.
+ */
+export const $$textContent = async (textContent: string, root?: puppeteer.JSHandle) => {
+ const {frontend} = getBrowserAndPages();
+ const rootElement = root ? root as puppeteer.ElementHandle : frontend;
+ const element = await rootElement.$$('pierceShadowText/' + textContent);
+ return element;
+};
+
export const timeout = (duration: number) => new Promise(resolve => setTimeout(resolve, duration));
export const waitFor = async (selector: string, root?: puppeteer.JSHandle, asyncScope = new AsyncScope()) => {
@@ -204,6 +217,18 @@
}, asyncScope));
};
+export const waitForElementsWithTextContent =
+ (textContent: string, root?: puppeteer.JSHandle, asyncScope = new AsyncScope()) => {
+ return asyncScope.exec(() => waitForFunction(async () => {
+ const elems = await $$textContent(textContent, root);
+ if (elems && elems.length) {
+ return elems;
+ }
+
+ return undefined;
+ }, asyncScope));
+ };
+
export const waitForFunction = async<T>(fn: () => Promise<T|undefined>, asyncScope = new AsyncScope()): Promise<T> => {
return await asyncScope.exec(async () => {
while (true) {