[go: nahoru, domu]

blob: b3de89b3a1442252415f0d3ddfa5222051821326 [file] [log] [blame]
// 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.
import {assert} from 'chai';
import {$$, click, getBrowserAndPages, goToResource, waitForElementsWithTextContent, waitForElementWithTextContent, waitForFunction} from '../../shared/helper.js';
import {describe, it} from '../../shared/mocha-extensions.js';
import {changeViewViaDropdown, findSearchResult, navigateToMemoryTab, setSearchFilter, takeHeapSnapshot, waitForNonEmptyHeapSnapshotData, waitForRetainerChain, waitForSearchResultNumber, waitUntilRetainerChainSatisfies} from '../helpers/memory-helpers.js';
describe('The Memory Panel', async function() {
// These tests render large chunks of data into DevTools and filter/search
// through it. On bots with less CPU power, these can fail because the
// rendering takes a long time, so we allow a larger timeout.
this.timeout(20000);
it('Loads content', async () => {
await goToResource('memory/default.html');
await navigateToMemoryTab();
});
it('Can take several heap snapshots ', async () => {
await goToResource('memory/default.html');
await navigateToMemoryTab();
await takeHeapSnapshot();
await waitForNonEmptyHeapSnapshotData();
await takeHeapSnapshot();
await waitForNonEmptyHeapSnapshotData();
const heapSnapShots = await $$('.heap-snapshot-sidebar-tree-item');
assert.strictEqual(heapSnapShots.length, 2);
});
it('Shows a DOM node and its JS wrapper as a single node', async () => {
await goToResource('memory/detached-node.html');
await navigateToMemoryTab();
await takeHeapSnapshot();
await waitForNonEmptyHeapSnapshotData();
await setSearchFilter('leaking');
await waitForSearchResultNumber(4);
await findSearchResult(async p => {
const el = await p.$(':scope > td > div > .object-value-function');
return !!el && await el.evaluate(el => el.textContent === 'leaking()');
});
await waitForRetainerChain([
'Detached V8EventListener',
'Detached EventListener',
'Detached InternalNode',
'Detached InternalNode',
'Detached HTMLDivElement',
'Retainer',
'Window /',
]);
});
it('Correctly retains the path for event listeners', async () => {
await goToResource('memory/event-listeners.html');
await navigateToMemoryTab();
await takeHeapSnapshot();
await waitForNonEmptyHeapSnapshotData();
await setSearchFilter('myEventListener');
await waitForSearchResultNumber(4);
await findSearchResult(async p => {
const el = await p.$(':scope > td > div > .object-value-function');
return !!el && await el.evaluate(el => el.textContent === 'myEventListener()');
});
await waitForRetainerChain([
'V8EventListener',
'EventListener',
'InternalNode',
'InternalNode',
'HTMLBodyElement',
'HTMLHtmlElement',
'HTMLDocument',
'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;
});
});
it('Shows the correct number of divs for a detached DOM tree correctly', async () => {
await goToResource('memory/detached-dom-tree.html');
await navigateToMemoryTab();
await takeHeapSnapshot();
await waitForNonEmptyHeapSnapshotData();
await setSearchFilter('Detached HTMLDivElement');
await waitForSearchResultNumber(3);
});
it('Shows the correct output for an attached iframe', async () => {
await goToResource('memory/attached-iframe.html');
await navigateToMemoryTab();
await takeHeapSnapshot();
await waitForNonEmptyHeapSnapshotData();
await setSearchFilter('Retainer');
await waitForSearchResultNumber(8);
await findSearchResult(async p => {
const el = await p.$(':scope > td > div > .object-value-object');
return !!el && await el.evaluate(el => el.textContent === 'Retainer');
});
// The following line checks two things: That the property 'aUniqueName'
// in the iframe is retaining the Retainer class object, and that the
// iframe window is not detached.
await waitUntilRetainerChainSatisfies(
retainerChain => retainerChain.some(
({propertyName, retainerClassName}) => propertyName === 'aUniqueName' && retainerClassName === 'Window /'));
});
});