UNPKG

@dcloudio/uni-debugger

Version:

uni-app debugger

717 lines (583 loc) 24.6 kB
// Copyright 2017 The Chromium Authors. All // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. /** * @fileoverview using private properties isn't a Closure violation in tests. * @suppress {accessControls} */ HeapProfilerTestRunner.createHeapSnapshotMockFactories = function() { HeapProfilerTestRunner.createJSHeapSnapshotMockObject = function() { return { _rootNodeIndex: 0, _nodeTypeOffset: 0, _nodeNameOffset: 1, _nodeEdgeCountOffset: 2, _nodeFieldCount: 3, _edgeFieldsCount: 3, _edgeTypeOffset: 0, _edgeNameOffset: 1, _edgeToNodeOffset: 2, _nodeTypes: ['hidden', 'object'], _edgeTypes: ['element', 'property', 'shortcut'], _edgeShortcutType: -1, _edgeHiddenType: -1, _edgeElementType: 0, _realNodesLength: 18, nodes: new Uint32Array([0, 0, 2, 1, 1, 2, 1, 2, 2, 1, 3, 1, 1, 4, 0, 1, 5, 0]), containmentEdges: new Uint32Array([2, 6, 3, 1, 7, 6, 0, 1, 6, 1, 8, 9, 1, 9, 9, 1, 10, 12, 1, 11, 15]), strings: ['', 'A', 'B', 'C', 'D', 'E', 'a', 'b', 'ac', 'bc', 'bd', 'ce'], _firstEdgeIndexes: new Uint32Array([0, 6, 12, 18, 21, 21, 21]), createNode: HeapSnapshotWorker.JSHeapSnapshot.prototype.createNode, createEdge: HeapSnapshotWorker.JSHeapSnapshot.prototype.createEdge, createRetainingEdge: HeapSnapshotWorker.JSHeapSnapshot.prototype.createRetainingEdge }; }; HeapProfilerTestRunner.createHeapSnapshotMockRaw = function() { return { snapshot: { meta: { node_fields: ['type', 'name', 'id', 'self_size', 'retained_size', 'dominator', 'edge_count'], node_types: [['hidden', 'object'], '', '', '', '', '', ''], edge_fields: ['type', 'name_or_index', 'to_node'], edge_types: [['element', 'property', 'shortcut'], '', ''] }, node_count: 6, edge_count: 7 }, nodes: [ 0, 0, 1, 0, 20, 0, 2, 1, 1, 2, 2, 2, 0, 2, 1, 2, 3, 3, 8, 0, 2, 1, 3, 4, 4, 10, 0, 1, 1, 4, 5, 5, 5, 14, 0, 1, 5, 6, 6, 6, 21, 0 ], edges: [1, 6, 7, 1, 7, 14, 0, 1, 14, 1, 8, 21, 1, 9, 21, 1, 10, 28, 1, 11, 35], strings: ['', 'A', 'B', 'C', 'D', 'E', 'a', 'b', 'ac', 'bc', 'bd', 'ce'] }; }; HeapProfilerTestRunner._postprocessHeapSnapshotMock = function(mock) { mock.nodes = new Uint32Array(mock.nodes); mock.edges = new Uint32Array(mock.edges); return mock; }; HeapProfilerTestRunner.createHeapSnapshotMock = function() { return HeapProfilerTestRunner._postprocessHeapSnapshotMock(HeapProfilerTestRunner.createHeapSnapshotMockRaw()); }; HeapProfilerTestRunner.createHeapSnapshotMockWithDOM = function() { return HeapProfilerTestRunner._postprocessHeapSnapshotMock({ snapshot: { meta: { node_fields: ['type', 'name', 'id', 'edge_count'], node_types: [['hidden', 'object', 'synthetic'], '', '', ''], edge_fields: ['type', 'name_or_index', 'to_node'], edge_types: [['element', 'hidden', 'internal'], '', ''] }, node_count: 13, edge_count: 13 }, nodes: [ 2, 0, 1, 4, 1, 11, 2, 2, 1, 11, 3, 3, 2, 5, 4, 0, 2, 6, 5, 1, 1, 1, 6, 0, 1, 2, 7, 1, 1, 4, 8, 2, 1, 8, 9, 0, 1, 7, 10, 0, 1, 3, 11, 0, 1, 10, 12, 0, 1, 9, 13, 0 ], edges: [ 0, 1, 4, 0, 2, 8, 0, 3, 12, 0, 4, 16, 0, 1, 20, 0, 2, 24, 0, 1, 24, 0, 2, 28, 1, 3, 32, 0, 1, 36, 0, 1, 40, 2, 12, 44, 2, 1, 48 ], strings: ['', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'M', 'N', 'Window', 'native'] }); }; HeapProfilerTestRunner.HeapNode = function(name, selfSize, type, id) { this._type = type || HeapProfilerTestRunner.HeapNode.Type.object; this._name = name; this._selfSize = selfSize || 0; this._builder = null; this._edges = {}; this._edgesCount = 0; this._id = id; }; HeapProfilerTestRunner.HeapNode.Type = { 'hidden': 'hidden', 'array': 'array', 'string': 'string', 'object': 'object', 'code': 'code', 'closure': 'closure', 'regexp': 'regexp', 'number': 'number', 'native': 'native', 'synthetic': 'synthetic', 'bigint': 'bigint' }; HeapProfilerTestRunner.HeapNode.prototype = { linkNode: function(node, type, nameOrIndex) { if (!this._builder) throw new Error('parent node is not connected to a snapshot'); if (!node._builder) node._setBuilder(this._builder); if (nameOrIndex === undefined) nameOrIndex = this._edgesCount; ++this._edgesCount; if (nameOrIndex in this._edges) { throw new Error( 'Can\'t add edge with the same nameOrIndex. nameOrIndex: ' + nameOrIndex + ' oldNodeName: ' + this._edges[nameOrIndex]._name + ' newNodeName: ' + node._name); } this._edges[nameOrIndex] = new HeapProfilerTestRunner.HeapEdge(node, type, nameOrIndex); }, _setBuilder: function(builder) { if (this._builder) throw new Error('node reusing is prohibited'); this._builder = builder; this._ordinal = this._builder._registerNode(this); }, _serialize: function(rawSnapshot) { rawSnapshot.nodes.push(this._builder.lookupNodeType(this._type)); rawSnapshot.nodes.push(this._builder.lookupOrAddString(this._name)); rawSnapshot.nodes.push(this._id || this._ordinal * 2 + 1); rawSnapshot.nodes.push(this._selfSize); rawSnapshot.nodes.push(0); rawSnapshot.nodes.push(0); rawSnapshot.nodes.push(Object.keys(this._edges).length); for (const i in this._edges) this._edges[i]._serialize(rawSnapshot); } }; HeapProfilerTestRunner.HeapEdge = function(targetNode, type, nameOrIndex) { this._targetNode = targetNode; this._type = type; this._nameOrIndex = nameOrIndex; }; HeapProfilerTestRunner.HeapEdge.prototype = { _serialize: function(rawSnapshot) { if (!this._targetNode._builder) throw new Error('Inconsistent state of node: ' + this._name + ' no builder assigned'); const builder = this._targetNode._builder; rawSnapshot.edges.push(builder.lookupEdgeType(this._type)); rawSnapshot.edges.push( (typeof this._nameOrIndex === 'string' ? builder.lookupOrAddString(this._nameOrIndex) : this._nameOrIndex)); rawSnapshot.edges.push(this._targetNode._ordinal * builder.nodeFieldsCount); } }; HeapProfilerTestRunner.HeapEdge.Type = { 'context': 'context', 'element': 'element', 'property': 'property', 'internal': 'internal', 'hidden': 'hidden', 'shortcut': 'shortcut', 'weak': 'weak' }; HeapProfilerTestRunner.HeapSnapshotBuilder = function() { this._nodes = []; this._string2id = {}; this._strings = []; this.nodeFieldsCount = 7; this._nodeTypesMap = {}; this._nodeTypesArray = []; for (const nodeType in HeapProfilerTestRunner.HeapNode.Type) { this._nodeTypesMap[nodeType] = this._nodeTypesArray.length; this._nodeTypesArray.push(nodeType); } this._edgeTypesMap = {}; this._edgeTypesArray = []; for (const edgeType in HeapProfilerTestRunner.HeapEdge.Type) { this._edgeTypesMap[edgeType] = this._edgeTypesArray.length; this._edgeTypesArray.push(edgeType); } this.rootNode = new HeapProfilerTestRunner.HeapNode('root', 0, 'object'); this.rootNode._setBuilder(this); }; HeapProfilerTestRunner.HeapSnapshotBuilder.prototype = { generateSnapshot: function() { const rawSnapshot = { 'snapshot': { 'meta': { 'node_fields': ['type', 'name', 'id', 'self_size', 'retained_size', 'dominator', 'edge_count'], 'node_types': [this._nodeTypesArray, 'string', 'number', 'number', 'number', 'number', 'number'], 'edge_fields': ['type', 'name_or_index', 'to_node'], 'edge_types': [this._edgeTypesArray, 'string_or_number', 'node'] } }, 'nodes': [], 'edges': [], 'strings': [] }; for (let i = 0; i < this._nodes.length; ++i) this._nodes[i]._serialize(rawSnapshot); rawSnapshot.strings = this._strings.slice(); const meta = rawSnapshot.snapshot.meta; rawSnapshot.snapshot.edge_count = rawSnapshot.edges.length / meta.edge_fields.length; rawSnapshot.snapshot.node_count = rawSnapshot.nodes.length / meta.node_fields.length; return rawSnapshot; }, createJSHeapSnapshot: function() { const parsedSnapshot = HeapProfilerTestRunner._postprocessHeapSnapshotMock(this.generateSnapshot()); return new HeapSnapshotWorker.JSHeapSnapshot(parsedSnapshot, new HeapSnapshotWorker.HeapSnapshotProgress()); }, _registerNode: function(node) { this._nodes.push(node); return this._nodes.length - 1; }, lookupNodeType: function(typeName) { if (typeName === undefined) throw new Error('wrong node type: ' + typeName); if (!(typeName in this._nodeTypesMap)) throw new Error('wrong node type name: ' + typeName); return this._nodeTypesMap[typeName]; }, lookupEdgeType: function(typeName) { if (!(typeName in this._edgeTypesMap)) throw new Error('wrong edge type name: ' + typeName); return this._edgeTypesMap[typeName]; }, lookupOrAddString: function(string) { if (string in this._string2id) return this._string2id[string]; this._string2id[string] = this._strings.length; this._strings.push(string); return this._strings.length - 1; } }; HeapProfilerTestRunner.createHeapSnapshot = function(instanceCount, firstId) { let seed = 881669; function pseudoRandom(limit) { seed = seed * 355109 + 153763 >> 2 & 65535; return seed % limit; } const builder = new HeapProfilerTestRunner.HeapSnapshotBuilder(); const rootNode = builder.rootNode; const gcRootsNode = new HeapProfilerTestRunner.HeapNode('(GC roots)', 0, HeapProfilerTestRunner.HeapNode.Type.synthetic); rootNode.linkNode(gcRootsNode, HeapProfilerTestRunner.HeapEdge.Type.element); const windowNode = new HeapProfilerTestRunner.HeapNode('Window', 20); rootNode.linkNode(windowNode, HeapProfilerTestRunner.HeapEdge.Type.shortcut); gcRootsNode.linkNode(windowNode, HeapProfilerTestRunner.HeapEdge.Type.element); for (let i = 0; i < instanceCount; ++i) { const sizeOfB = pseudoRandom(20) + 1; const nodeB = new HeapProfilerTestRunner.HeapNode('B', sizeOfB, undefined, firstId++); windowNode.linkNode(nodeB, HeapProfilerTestRunner.HeapEdge.Type.element); const sizeOfA = pseudoRandom(50) + 1; const nodeA = new HeapProfilerTestRunner.HeapNode('A', sizeOfA, undefined, firstId++); nodeB.linkNode(nodeA, HeapProfilerTestRunner.HeapEdge.Type.property, 'a'); nodeA.linkNode(nodeA, HeapProfilerTestRunner.HeapEdge.Type.property, 'a'); } return builder.generateSnapshot(); }; }; HeapProfilerTestRunner.createHeapSnapshotMockFactories(); HeapProfilerTestRunner.startProfilerTest = function(callback) { TestRunner.addResult('Profiler was enabled.'); HeapProfilerTestRunner._panelReset = TestRunner.override(UI.panels.heap_profiler, '_reset', function() {}, true); TestRunner.addSniffer(UI.panels.heap_profiler, '_addProfileHeader', HeapProfilerTestRunner._profileHeaderAdded, true); TestRunner.addSniffer(Profiler.ProfileView.prototype, 'refresh', HeapProfilerTestRunner._profileViewRefresh, true); TestRunner.addSniffer(Profiler.HeapSnapshotView.prototype, 'show', HeapProfilerTestRunner._snapshotViewShown, true); Profiler.HeapSnapshotContainmentDataGrid.prototype.defaultPopulateCount = function() { return 10; }; Profiler.HeapSnapshotConstructorsDataGrid.prototype.defaultPopulateCount = function() { return 10; }; Profiler.HeapSnapshotDiffDataGrid.prototype.defaultPopulateCount = function() { return 5; }; TestRunner.addResult('Detailed heap profiles were enabled.'); TestRunner.safeWrap(callback)(); }; HeapProfilerTestRunner.completeProfilerTest = function() { TestRunner.addResult(''); TestRunner.addResult('Profiler was disabled.'); TestRunner.completeTest(); }; HeapProfilerTestRunner.runHeapSnapshotTestSuite = function(testSuite) { const testSuiteTests = testSuite.slice(); let completeTestStack; function runner() { if (!testSuiteTests.length) { if (completeTestStack) TestRunner.addResult('FAIL: test already completed at ' + completeTestStack); HeapProfilerTestRunner.completeProfilerTest(); completeTestStack = new Error().stack; return; } const nextTest = testSuiteTests.shift(); TestRunner.addResult(''); TestRunner.addResult( 'Running: ' + /function\s([^(]*)/.exec(nextTest)[1]); HeapProfilerTestRunner._panelReset.call(UI.panels.heap_profiler); TestRunner.safeWrap(nextTest)(runner, runner); } HeapProfilerTestRunner.startProfilerTest(runner); }; HeapProfilerTestRunner.assertColumnContentsEqual = function(reference, actual) { const length = Math.min(reference.length, actual.length); for (let i = 0; i < length; ++i) TestRunner.assertEquals(reference[i], actual[i], 'row ' + i); if (reference.length > length) TestRunner.addResult('extra rows in reference array:\n' + reference.slice(length).join('\n')); else if (actual.length > length) TestRunner.addResult('extra rows in actual array:\n' + actual.slice(length).join('\n')); }; HeapProfilerTestRunner.checkArrayIsSorted = function(contents, sortType, sortOrder) { function simpleComparator(a, b) { return (a < b ? -1 : (a > b ? 1 : 0)); } function parseSize(size) { return parseInt(size.replace(/[\xa0,]/g, ''), 10); } const extractor = { text: function(data) { data; }, number: function(data) { return parseInt(data, 10); }, size: parseSize, name: function(data) { return data; }, id: function(data) { return parseInt(data, 10); } }[sortType]; if (!extractor) { TestRunner.addResult('Invalid sort type: ' + sortType); return; } let acceptableComparisonResult; if (sortOrder === DataGrid.DataGrid.Order.Ascending) { acceptableComparisonResult = -1; } else if (sortOrder === DataGrid.DataGrid.Order.Descending) { acceptableComparisonResult = 1; } else { TestRunner.addResult('Invalid sort order: ' + sortOrder); return; } for (let i = 0; i < contents.length - 1; ++i) { const a = extractor(contents[i]); const b = extractor(contents[i + 1]); const result = simpleComparator(a, b); if (result !== 0 && result !== acceptableComparisonResult) { TestRunner.addResult( 'Elements ' + i + ' and ' + (i + 1) + ' are out of order: ' + a + ' ' + b + ' (' + sortOrder + ')'); } } }; HeapProfilerTestRunner.clickColumn = function(column, callback) { callback = TestRunner.safeWrap(callback); const cell = this._currentGrid()._headerTableHeaders[column.id]; const event = { target: { enclosingNodeOrSelfWithNodeName: function() { return cell; } } }; function sortingComplete() { HeapProfilerTestRunner._currentGrid().removeEventListener( Profiler.HeapSnapshotSortableDataGrid.Events.SortingComplete, sortingComplete, this); TestRunner.assertEquals(column.id, this._currentGrid().sortColumnId(), 'unexpected sorting'); column.sort = this._currentGrid().sortOrder(); function callCallback() { callback(column); } setTimeout(callCallback, 0); } HeapProfilerTestRunner._currentGrid().addEventListener( Profiler.HeapSnapshotSortableDataGrid.Events.SortingComplete, sortingComplete, this); this._currentGrid()._clickInHeaderCell(event); }; HeapProfilerTestRunner.clickRowAndGetRetainers = function(row, callback) { callback = TestRunner.safeWrap(callback); const event = { target: { enclosingNodeOrSelfWithNodeName: function() { return row._element; }, selectedNode: row } }; this._currentGrid()._mouseDownInDataTable(event); const rootNode = HeapProfilerTestRunner.currentProfileView()._retainmentDataGrid.rootNode(); rootNode.once(Profiler.HeapSnapshotGridNode.Events.PopulateComplete).then(() => callback(rootNode)); }; HeapProfilerTestRunner.clickShowMoreButton = function(buttonName, row, callback) { callback = TestRunner.safeWrap(callback); const parent = row.parent; parent.once(Profiler.HeapSnapshotGridNode.Events.PopulateComplete).then(() => setTimeout(() => callback(parent), 0)); row[buttonName].click(); }; HeapProfilerTestRunner.columnContents = function(column, row) { this._currentGrid().updateVisibleNodes(); const columnOrdinal = HeapProfilerTestRunner.viewColumns().indexOf(column); const result = []; const parent = row || this._currentGrid().rootNode(); for (let node = parent.children[0]; node; node = node.traverseNextNode(true, parent, true)) { if (!node.selectable) continue; let content = node.element().children[columnOrdinal]; if (content.firstElementChild) content = content.firstElementChild; result.push(content.textContent); } return result; }; HeapProfilerTestRunner.countDataRows = function(row, filter) { let result = 0; filter = filter || function(node) { return node.selectable; }; for (let node = row.children[0]; node; node = node.traverseNextNode(true, row, true)) { if (filter(node)) ++result; } return result; }; HeapProfilerTestRunner.expandRow = function(row, callback) { callback = TestRunner.safeWrap(callback); row.once(Profiler.HeapSnapshotGridNode.Events.PopulateComplete).then(() => setTimeout(() => callback(row), 0)); (function expand() { if (row.hasChildren()) row.expand(); else setTimeout(expand, 0); })(); }; HeapProfilerTestRunner.expandRowPromise = function(row) { return new Promise(resolve => HeapProfilerTestRunner.expandRow(row, resolve)); }; HeapProfilerTestRunner.findAndExpandGCRoots = function(callback) { HeapProfilerTestRunner.findAndExpandRow('(GC roots)', callback); }; HeapProfilerTestRunner.findAndExpandWindow = function(callback) { HeapProfilerTestRunner.findAndExpandRow('Window', callback); }; HeapProfilerTestRunner.findAndExpandRow = async function(name, callback) { const row = HeapProfilerTestRunner.findRow(name); TestRunner.assertEquals(true, !!row, `"${name}" row`); await HeapProfilerTestRunner.expandRowPromise(row); TestRunner.safeWrap(callback)(row); return row; }; HeapProfilerTestRunner.findButtonsNode = function(row, startNode) { for (let node = startNode || row.children[0]; node; node = node.traverseNextNode(true, row, true)) { if (!node.selectable && node.showNext) return node; } return null; }; HeapProfilerTestRunner.findRow = function(name, parent) { return HeapProfilerTestRunner.findMatchingRow(node => node._name === name, parent); }; HeapProfilerTestRunner.findMatchingRow = function(matcher, parent) { parent = parent || this._currentGrid().rootNode(); for (let node = parent.children[0]; node; node = node.traverseNextNode(true, parent, true)) { if (matcher(node)) return node; } return null; }; HeapProfilerTestRunner.switchToView = function(title, callback) { return new Promise(resolve => { callback = TestRunner.safeWrap(callback); const view = UI.panels.heap_profiler.visibleView; view._changePerspectiveAndWait(title).then(callback).then(resolve); HeapProfilerTestRunner._currentGrid().scrollContainer.style.height = '10000px'; }); }; HeapProfilerTestRunner.takeAndOpenSnapshot = async function(generator, callback) { callback = TestRunner.safeWrap(callback); const snapshot = generator(); const profileType = Profiler.ProfileTypeRegistry.instance.heapSnapshotProfileType; function pushGeneratedSnapshot(reportProgress) { if (reportProgress) { profileType._reportHeapSnapshotProgress({data: {done: 50, total: 100, finished: false}}); profileType._reportHeapSnapshotProgress({data: {done: 100, total: 100, finished: true}}); } snapshot.snapshot.typeId = 'HEAP'; profileType._addHeapSnapshotChunk({data: JSON.stringify(snapshot)}); return Promise.resolve(); } HeapProfilerTestRunner._takeAndOpenSnapshotCallback = callback; TestRunner.override(TestRunner.HeapProfilerAgent, 'takeHeapSnapshot', pushGeneratedSnapshot); if (!UI.context.flavor(SDK.HeapProfilerModel)) await new Promise(resolve => UI.context.addFlavorChangeListener(SDK.HeapProfilerModel, resolve)); profileType._takeHeapSnapshot(); }; /** * @return {!Promise<!Profiler.HeapProfileHeader>} */ HeapProfilerTestRunner.takeSnapshotPromise = function() { return new Promise(resolve => { const heapProfileType = Profiler.ProfileTypeRegistry.instance.heapSnapshotProfileType; heapProfileType.addEventListener(Profiler.HeapSnapshotProfileType.SnapshotReceived, finishHeapSnapshot); heapProfileType._takeHeapSnapshot(); function finishHeapSnapshot() { const profiles = heapProfileType.getProfiles(); if (!profiles.length) throw 'FAILED: no profiles found.'; if (profiles.length > 1) throw `FAILED: wrong number of recorded profiles was found. profiles.length = ${profiles.length}`; const profile = profiles[0]; UI.panels.heap_profiler.showProfile(profile); const dataGrid = HeapProfilerTestRunner.currentProfileView()._dataGrid; dataGrid.addEventListener(Profiler.HeapSnapshotSortableDataGrid.Events.SortingComplete, sortingComplete, null); function sortingComplete() { dataGrid.removeEventListener( Profiler.HeapSnapshotSortableDataGrid.Events.SortingComplete, sortingComplete, null); resolve(profile); } } }); }; HeapProfilerTestRunner.viewColumns = function() { return HeapProfilerTestRunner._currentGrid()._columnsArray; }; HeapProfilerTestRunner.currentProfileView = function() { return UI.panels.heap_profiler.visibleView; }; HeapProfilerTestRunner._currentGrid = function() { return this.currentProfileView()._dataGrid; }; HeapProfilerTestRunner._snapshotViewShown = function() { if (HeapProfilerTestRunner._takeAndOpenSnapshotCallback) { const callback = HeapProfilerTestRunner._takeAndOpenSnapshotCallback; HeapProfilerTestRunner._takeAndOpenSnapshotCallback = null; const dataGrid = this._dataGrid; function sortingComplete() { dataGrid.removeEventListener(Profiler.HeapSnapshotSortableDataGrid.Events.SortingComplete, sortingComplete, null); callback(); } dataGrid.addEventListener(Profiler.HeapSnapshotSortableDataGrid.Events.SortingComplete, sortingComplete, null); } }; HeapProfilerTestRunner.showProfileWhenAdded = function(title) { HeapProfilerTestRunner._showProfileWhenAdded = title; return new Promise(resolve => HeapProfilerTestRunner._waitUntilProfileViewIsShown(title, resolve)); }; HeapProfilerTestRunner._profileHeaderAdded = function(profile) { if (HeapProfilerTestRunner._showProfileWhenAdded === profile.title) UI.panels.heap_profiler.showProfile(profile); }; HeapProfilerTestRunner._waitUntilProfileViewIsShown = function(title, callback) { callback = TestRunner.safeWrap(callback); const profilesPanel = UI.panels.heap_profiler; if (profilesPanel.visibleView && profilesPanel.visibleView.profile && profilesPanel.visibleView._profileHeader.title === title) callback(profilesPanel.visibleView); else HeapProfilerTestRunner._waitUntilProfileViewIsShownCallback = {title: title, callback: callback}; }; HeapProfilerTestRunner._profileViewRefresh = function() { if (HeapProfilerTestRunner._waitUntilProfileViewIsShownCallback && HeapProfilerTestRunner._waitUntilProfileViewIsShownCallback.title === this._profileHeader.title) { const callback = HeapProfilerTestRunner._waitUntilProfileViewIsShownCallback; delete HeapProfilerTestRunner._waitUntilProfileViewIsShownCallback; callback.callback(this); } }; HeapProfilerTestRunner.startSamplingHeapProfiler = async function() { if (!UI.context.flavor(SDK.HeapProfilerModel)) await new Promise(resolve => UI.context.addFlavorChangeListener(SDK.HeapProfilerModel, resolve)); Profiler.SamplingHeapProfileType.instance.startRecordingProfile(); }; HeapProfilerTestRunner.stopSamplingHeapProfiler = function() { Profiler.SamplingHeapProfileType.instance.stopRecordingProfile(); };