|  | // 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} | 
|  | */ | 
|  |  | 
|  | SourcesTestRunner.startDebuggerTest = function(callback, quiet) { | 
|  | console.assert(TestRunner.debuggerModel.debuggerEnabled(), 'Debugger has to be enabled'); | 
|  |  | 
|  | if (quiet !== undefined) { | 
|  | SourcesTestRunner._quiet = quiet; | 
|  | } | 
|  |  | 
|  | UI.viewManager.showView('sources'); | 
|  | TestRunner.addSniffer(SDK.DebuggerModel.prototype, '_pausedScript', SourcesTestRunner._pausedScript, true); | 
|  | TestRunner.addSniffer(SDK.DebuggerModel.prototype, '_resumedScript', SourcesTestRunner._resumedScript, true); | 
|  | TestRunner.safeWrap(callback)(); | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.startDebuggerTestPromise = function(quiet) { | 
|  | let cb; | 
|  | const p = new Promise(fullfill => cb = fullfill); | 
|  | SourcesTestRunner.startDebuggerTest(cb, quiet); | 
|  | return p; | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.completeDebuggerTest = function() { | 
|  | Common.moduleSetting('breakpointsActive').set(true); | 
|  | SourcesTestRunner.resumeExecution(TestRunner.completeTest.bind(TestRunner)); | 
|  | }; | 
|  |  | 
|  | (function() { | 
|  | const origThen = Promise.prototype.then; | 
|  | const origCatch = Promise.prototype.catch; | 
|  |  | 
|  | Promise.prototype.then = function() { | 
|  | const result = origThen.apply(this, arguments); | 
|  | origThen.call(result, undefined, onUncaughtPromiseReject.bind(null, new Error().stack)); | 
|  | return result; | 
|  | }; | 
|  |  | 
|  | Promise.prototype.catch = function() { | 
|  | const result = origCatch.apply(this, arguments); | 
|  | origThen.call(result, undefined, onUncaughtPromiseReject.bind(null, new Error().stack)); | 
|  | return result; | 
|  | }; | 
|  |  | 
|  | function onUncaughtPromiseReject(stack, e) { | 
|  | const message = typeof e === 'object' && e.stack || e; | 
|  | TestRunner.addResult('FAIL: Uncaught exception in promise: ' + message + ' ' + stack); | 
|  | SourcesTestRunner.completeDebuggerTest(); | 
|  | } | 
|  | })(); | 
|  |  | 
|  | SourcesTestRunner.runDebuggerTestSuite = function(testSuite) { | 
|  | const testSuiteTests = testSuite.slice(); | 
|  |  | 
|  | function runner() { | 
|  | if (!testSuiteTests.length) { | 
|  | SourcesTestRunner.completeDebuggerTest(); | 
|  | return; | 
|  | } | 
|  |  | 
|  | const nextTest = testSuiteTests.shift(); | 
|  | TestRunner.addResult(''); | 
|  | TestRunner.addResult( | 
|  | 'Running: ' + | 
|  | /function\s([^(]*)/.exec(nextTest)[1]); | 
|  | TestRunner.safeWrap(nextTest)(runner, runner); | 
|  | } | 
|  |  | 
|  | SourcesTestRunner.startDebuggerTest(runner); | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.runTestFunction = function() { | 
|  | TestRunner.evaluateInPageAnonymously('scheduleTestFunction()'); | 
|  | TestRunner.addResult('Set timer for test function.'); | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.runTestFunctionAndWaitUntilPaused = function(callback) { | 
|  | SourcesTestRunner.runTestFunction(); | 
|  | SourcesTestRunner.waitUntilPaused(callback); | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.runTestFunctionAndWaitUntilPausedPromise = function() { | 
|  | return new Promise(SourcesTestRunner.runTestFunctionAndWaitUntilPaused); | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.runAsyncCallStacksTest = function(totalDebuggerStatements, maxAsyncCallStackDepth) { | 
|  | const defaultMaxAsyncCallStackDepth = 32; | 
|  | SourcesTestRunner.setQuiet(true); | 
|  | SourcesTestRunner.startDebuggerTest(step1); | 
|  |  | 
|  | async function step1() { | 
|  | await TestRunner.DebuggerAgent.setAsyncCallStackDepth(maxAsyncCallStackDepth || defaultMaxAsyncCallStackDepth); | 
|  | SourcesTestRunner.runTestFunctionAndWaitUntilPaused(didPause); | 
|  | } | 
|  |  | 
|  | let step = 0; | 
|  | const callStacksOutput = []; | 
|  |  | 
|  | function didPause(callFrames, reason, breakpointIds, asyncStackTrace) { | 
|  | ++step; | 
|  | callStacksOutput.push(SourcesTestRunner.captureStackTraceIntoString(callFrames, asyncStackTrace) + '\n'); | 
|  |  | 
|  | if (step < totalDebuggerStatements) { | 
|  | SourcesTestRunner.resumeExecution(SourcesTestRunner.waitUntilPaused.bind(SourcesTestRunner, didPause)); | 
|  | } else { | 
|  | TestRunner.addResult('Captured call stacks in no particular order:'); | 
|  | callStacksOutput.sort(); | 
|  | TestRunner.addResults(callStacksOutput); | 
|  | SourcesTestRunner.completeDebuggerTest(); | 
|  | } | 
|  | } | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.dumpSourceFrameMessages = function(sourceFrame, dumpFullURL) { | 
|  | const messages = []; | 
|  |  | 
|  | for (const bucket of sourceFrame._rowMessageBuckets.values()) { | 
|  | for (const rowMessage of bucket._messages) { | 
|  | const message = rowMessage.message(); | 
|  | messages.push(String.sprintf( | 
|  | '  %d:%d [%s] %s', message.lineNumber(), message.columnNumber(), message.level(), message.text())); | 
|  | } | 
|  | } | 
|  |  | 
|  | const name = (dumpFullURL ? sourceFrame.uiSourceCode().url() : sourceFrame.uiSourceCode().displayName()); | 
|  | TestRunner.addResult('SourceFrame ' + name + ': ' + messages.length + ' message(s)'); | 
|  | TestRunner.addResult(messages.join('\n')); | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.waitUntilPausedNextTime = function(callback) { | 
|  | SourcesTestRunner._waitUntilPausedCallback = TestRunner.safeWrap(callback); | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.waitUntilPaused = function(callback) { | 
|  | callback = TestRunner.safeWrap(callback); | 
|  |  | 
|  | if (SourcesTestRunner._pausedScriptArguments) { | 
|  | callback.apply(callback, SourcesTestRunner._pausedScriptArguments); | 
|  | } else { | 
|  | SourcesTestRunner._waitUntilPausedCallback = callback; | 
|  | } | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.waitUntilPausedPromise = function() { | 
|  | return new Promise(resolve => SourcesTestRunner.waitUntilPaused(resolve)); | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.waitUntilResumedNextTime = function(callback) { | 
|  | SourcesTestRunner._waitUntilResumedCallback = TestRunner.safeWrap(callback); | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.waitUntilResumed = function(callback) { | 
|  | callback = TestRunner.safeWrap(callback); | 
|  |  | 
|  | if (!SourcesTestRunner._pausedScriptArguments) { | 
|  | callback(); | 
|  | } else { | 
|  | SourcesTestRunner._waitUntilResumedCallback = callback; | 
|  | } | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.waitUntilResumedPromise = function() { | 
|  | return new Promise(resolve => SourcesTestRunner.waitUntilResumed(resolve)); | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.resumeExecution = function(callback) { | 
|  | if (UI.panels.sources.paused()) { | 
|  | UI.panels.sources._togglePause(); | 
|  | } | 
|  |  | 
|  | SourcesTestRunner.waitUntilResumed(callback); | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.waitUntilPausedAndDumpStackAndResume = function(callback, options) { | 
|  | SourcesTestRunner.waitUntilPaused(paused); | 
|  | TestRunner.addSniffer(Sources.SourcesPanel.prototype, '_updateDebuggerButtonsAndStatusForTest', setStatus); | 
|  | let caption; | 
|  | let callFrames; | 
|  | let asyncStackTrace; | 
|  |  | 
|  | function setStatus() { | 
|  | const statusElement = this.element.querySelector('.paused-message'); | 
|  | caption = statusElement.deepTextContent(); | 
|  |  | 
|  | if (callFrames) { | 
|  | step1(); | 
|  | } | 
|  | } | 
|  |  | 
|  | function paused(frames, reason, breakpointIds, async) { | 
|  | callFrames = frames; | 
|  | asyncStackTrace = async; | 
|  |  | 
|  | if (typeof caption === 'string') { | 
|  | step1(); | 
|  | } | 
|  | } | 
|  |  | 
|  | function step1() { | 
|  | SourcesTestRunner.captureStackTrace(callFrames, asyncStackTrace, options); | 
|  | TestRunner.addResult(TestRunner.clearSpecificInfoFromStackFrames(caption)); | 
|  | TestRunner.deprecatedRunAfterPendingDispatches(step2); | 
|  | } | 
|  |  | 
|  | function step2() { | 
|  | SourcesTestRunner.resumeExecution(TestRunner.safeWrap(callback)); | 
|  | } | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.stepOver = function() { | 
|  | Promise.resolve().then(function() { | 
|  | UI.panels.sources._stepOver(); | 
|  | }); | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.stepInto = function() { | 
|  | Promise.resolve().then(function() { | 
|  | UI.panels.sources._stepInto(); | 
|  | }); | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.stepIntoAsync = function() { | 
|  | Promise.resolve().then(function() { | 
|  | UI.panels.sources._stepIntoAsync(); | 
|  | }); | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.stepOut = function() { | 
|  | Promise.resolve().then(function() { | 
|  | UI.panels.sources._stepOut(); | 
|  | }); | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.togglePause = function() { | 
|  | Promise.resolve().then(function() { | 
|  | UI.panels.sources._togglePause(); | 
|  | }); | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.waitUntilPausedAndPerformSteppingActions = function(actions, callback) { | 
|  | callback = TestRunner.safeWrap(callback); | 
|  | SourcesTestRunner.waitUntilPaused(didPause); | 
|  |  | 
|  | function didPause(callFrames, reason, breakpointIds, asyncStackTrace) { | 
|  | let action = actions.shift(); | 
|  |  | 
|  | if (action === 'Print') { | 
|  | SourcesTestRunner.captureStackTrace(callFrames, asyncStackTrace); | 
|  | TestRunner.addResult(''); | 
|  |  | 
|  | while (action === 'Print') { | 
|  | action = actions.shift(); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!action) { | 
|  | callback(); | 
|  | return; | 
|  | } | 
|  |  | 
|  | TestRunner.addResult('Executing ' + action + '...'); | 
|  |  | 
|  | switch (action) { | 
|  | case 'StepInto': | 
|  | SourcesTestRunner.stepInto(); | 
|  | break; | 
|  | case 'StepOver': | 
|  | SourcesTestRunner.stepOver(); | 
|  | break; | 
|  | case 'StepOut': | 
|  | SourcesTestRunner.stepOut(); | 
|  | break; | 
|  | case 'Resume': | 
|  | SourcesTestRunner.togglePause(); | 
|  | break; | 
|  | default: | 
|  | TestRunner.addResult('FAIL: Unknown action: ' + action); | 
|  | callback(); | 
|  | return; | 
|  | } | 
|  |  | 
|  | SourcesTestRunner.waitUntilResumed( | 
|  | (actions.length ? SourcesTestRunner.waitUntilPaused.bind(SourcesTestRunner, didPause) : callback)); | 
|  | } | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.captureStackTrace = function(callFrames, asyncStackTrace, options) { | 
|  | TestRunner.addResult(SourcesTestRunner.captureStackTraceIntoString(callFrames, asyncStackTrace, options)); | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.captureStackTraceIntoString = function(callFrames, asyncStackTrace, options) { | 
|  | const results = []; | 
|  | options = options || {}; | 
|  |  | 
|  | function printCallFrames(callFrames, locationFunction, returnValueFunction) { | 
|  | let printed = 0; | 
|  |  | 
|  | for (let i = 0; i < callFrames.length; i++) { | 
|  | const frame = callFrames[i]; | 
|  | const location = locationFunction.call(frame); | 
|  | const script = location.script(); | 
|  | const uiLocation = Bindings.debuggerWorkspaceBinding.rawLocationToUILocation(location); | 
|  | const isFramework = | 
|  | uiLocation ? Bindings.blackboxManager.isBlackboxedUISourceCode(uiLocation.uiSourceCode) : false; | 
|  |  | 
|  | if (options.dropFrameworkCallFrames && isFramework) { | 
|  | continue; | 
|  | } | 
|  |  | 
|  | let url; | 
|  | let lineNumber; | 
|  |  | 
|  | if (uiLocation && uiLocation.uiSourceCode.project().type() !== Workspace.projectTypes.Debugger) { | 
|  | url = uiLocation.uiSourceCode.name(); | 
|  | lineNumber = uiLocation.lineNumber + 1; | 
|  | } else { | 
|  | url = Bindings.displayNameForURL(script.sourceURL); | 
|  | lineNumber = location.lineNumber + 1; | 
|  | } | 
|  |  | 
|  | let s = ((isFramework ? '  * ' : '    ')) + printed++ + ') ' + frame.functionName + ' (' + url + | 
|  | ((options.dropLineNumbers ? '' : ':' + lineNumber)) + ')'; | 
|  | s = s.replace(/scheduleTestFunction.+$/, 'scheduleTestFunction <omitted>'); | 
|  | results.push(s); | 
|  |  | 
|  | if (options.printReturnValue && returnValueFunction && returnValueFunction.call(frame)) { | 
|  | results.push('       <return>: ' + returnValueFunction.call(frame).description); | 
|  | } | 
|  |  | 
|  | if (frame.functionName === 'scheduleTestFunction') { | 
|  | const remainingFrames = callFrames.length - 1 - i; | 
|  |  | 
|  | if (remainingFrames) { | 
|  | results.push('    <... skipped remaining frames ...>'); | 
|  | } | 
|  |  | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | return printed; | 
|  | } | 
|  |  | 
|  | function runtimeCallFramePosition() { | 
|  | return new SDK.DebuggerModel.Location(TestRunner.debuggerModel, this.scriptId, this.lineNumber, this.columnNumber); | 
|  | } | 
|  |  | 
|  | results.push('Call stack:'); | 
|  | printCallFrames( | 
|  | callFrames, SDK.DebuggerModel.CallFrame.prototype.location, SDK.DebuggerModel.CallFrame.prototype.returnValue); | 
|  |  | 
|  | while (asyncStackTrace) { | 
|  | results.push('    [' + (asyncStackTrace.description || 'Async Call') + ']'); | 
|  | const printed = printCallFrames(asyncStackTrace.callFrames, runtimeCallFramePosition); | 
|  |  | 
|  | if (!printed) { | 
|  | results.pop(); | 
|  | } | 
|  |  | 
|  | asyncStackTrace = asyncStackTrace.parent; | 
|  | } | 
|  |  | 
|  | return results.join('\n'); | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.dumpSourceFrameContents = function(sourceFrame) { | 
|  | TestRunner.addResult('==Source frame contents start=='); | 
|  | const textEditor = sourceFrame._textEditor; | 
|  |  | 
|  | for (let i = 0; i < textEditor.linesCount; ++i) { | 
|  | TestRunner.addResult(textEditor.line(i)); | 
|  | } | 
|  |  | 
|  | TestRunner.addResult('==Source frame contents end=='); | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner._pausedScript = function(callFrames, reason, auxData, breakpointIds, asyncStackTrace) { | 
|  | if (!SourcesTestRunner._quiet) { | 
|  | TestRunner.addResult('Script execution paused.'); | 
|  | } | 
|  |  | 
|  | const debuggerModel = this.target().model(SDK.DebuggerModel); | 
|  | SourcesTestRunner._pausedScriptArguments = [ | 
|  | SDK.DebuggerModel.CallFrame.fromPayloadArray(debuggerModel, callFrames), reason, breakpointIds, asyncStackTrace, | 
|  | auxData | 
|  | ]; | 
|  |  | 
|  | if (SourcesTestRunner._waitUntilPausedCallback) { | 
|  | const callback = SourcesTestRunner._waitUntilPausedCallback; | 
|  | delete SourcesTestRunner._waitUntilPausedCallback; | 
|  | setTimeout(() => callback.apply(callback, SourcesTestRunner._pausedScriptArguments)); | 
|  | } | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner._resumedScript = function() { | 
|  | if (!SourcesTestRunner._quiet) { | 
|  | TestRunner.addResult('Script execution resumed.'); | 
|  | } | 
|  |  | 
|  | delete SourcesTestRunner._pausedScriptArguments; | 
|  |  | 
|  | if (SourcesTestRunner._waitUntilResumedCallback) { | 
|  | const callback = SourcesTestRunner._waitUntilResumedCallback; | 
|  | delete SourcesTestRunner._waitUntilResumedCallback; | 
|  | callback(); | 
|  | } | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.showUISourceCode = function(uiSourceCode, callback) { | 
|  | const panel = UI.panels.sources; | 
|  | panel.showUISourceCode(uiSourceCode); | 
|  | const sourceFrame = panel.visibleView; | 
|  |  | 
|  | if (sourceFrame.loaded) { | 
|  | callback(sourceFrame); | 
|  | } else { | 
|  | TestRunner.addSniffer(sourceFrame, 'setContent', callback && callback.bind(null, sourceFrame)); | 
|  | } | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.showUISourceCodePromise = function(uiSourceCode) { | 
|  | let fulfill; | 
|  | const promise = new Promise(x => fulfill = x); | 
|  | SourcesTestRunner.showUISourceCode(uiSourceCode, fulfill); | 
|  | return promise; | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.showScriptSource = function(scriptName, callback) { | 
|  | SourcesTestRunner.waitForScriptSource(scriptName, onScriptSource); | 
|  |  | 
|  | function onScriptSource(uiSourceCode) { | 
|  | SourcesTestRunner.showUISourceCode(uiSourceCode, callback); | 
|  | } | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.showScriptSourcePromise = function(scriptName) { | 
|  | return new Promise(resolve => SourcesTestRunner.showScriptSource(scriptName, resolve)); | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.waitForScriptSource = function(scriptName, callback) { | 
|  | const panel = UI.panels.sources; | 
|  | const uiSourceCodes = panel._workspace.uiSourceCodes(); | 
|  |  | 
|  | for (let i = 0; i < uiSourceCodes.length; ++i) { | 
|  | if (uiSourceCodes[i].project().type() === Workspace.projectTypes.Service) { | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (uiSourceCodes[i].name() === scriptName) { | 
|  | callback(uiSourceCodes[i]); | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | TestRunner.addSniffer( | 
|  | Sources.SourcesView.prototype, '_addUISourceCode', | 
|  | SourcesTestRunner.waitForScriptSource.bind(SourcesTestRunner, scriptName, callback)); | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.objectForPopover = function(sourceFrame, lineNumber, columnNumber) { | 
|  | const debuggerPlugin = SourcesTestRunner.debuggerPlugin(sourceFrame); | 
|  | const {x, y} = debuggerPlugin._textEditor.cursorPositionToCoordinates(lineNumber, columnNumber); | 
|  | const promise = TestRunner.addSnifferPromise(ObjectUI.ObjectPopoverHelper, 'buildObjectPopover'); | 
|  | debuggerPlugin._getPopoverRequest({x, y}).show(new UI.GlassPane()); | 
|  | return promise; | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.setBreakpoint = function(sourceFrame, lineNumber, condition, enabled) { | 
|  | const debuggerPlugin = SourcesTestRunner.debuggerPlugin(sourceFrame); | 
|  | if (!debuggerPlugin._muted) { | 
|  | debuggerPlugin._setBreakpoint(lineNumber, 0, condition, enabled); | 
|  | } | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.removeBreakpoint = function(sourceFrame, lineNumber) { | 
|  | const debuggerPlugin = SourcesTestRunner.debuggerPlugin(sourceFrame); | 
|  | const breakpointLocations = debuggerPlugin._breakpointManager.allBreakpointLocations(); | 
|  | const breakpointLocation = breakpointLocations.find( | 
|  | breakpointLocation => breakpointLocation.uiLocation.uiSourceCode === sourceFrame._uiSourceCode && | 
|  | breakpointLocation.uiLocation.lineNumber === lineNumber); | 
|  | breakpointLocation.breakpoint.remove(); | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.createNewBreakpoint = function(sourceFrame, lineNumber, condition, enabled) { | 
|  | const debuggerPlugin = SourcesTestRunner.debuggerPlugin(sourceFrame); | 
|  | const promise = | 
|  | new Promise(resolve => TestRunner.addSniffer(debuggerPlugin.__proto__, '_breakpointWasSetForTest', resolve)); | 
|  | debuggerPlugin._createNewBreakpoint(lineNumber, condition, enabled); | 
|  | return promise; | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.toggleBreakpoint = function(sourceFrame, lineNumber, disableOnly) { | 
|  | const debuggerPlugin = SourcesTestRunner.debuggerPlugin(sourceFrame); | 
|  | if (!debuggerPlugin._muted) { | 
|  | debuggerPlugin._toggleBreakpoint(lineNumber, disableOnly); | 
|  | } | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.waitBreakpointSidebarPane = function(waitUntilResolved) { | 
|  | return new Promise( | 
|  | resolve => TestRunner.addSniffer( | 
|  | Sources.JavaScriptBreakpointsSidebarPane.prototype, '_didUpdateForTest', resolve)) | 
|  | .then(checkIfReady); | 
|  |  | 
|  | function checkIfReady() { | 
|  | if (!waitUntilResolved) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | for (const {breakpoint} of Bindings.breakpointManager.allBreakpointLocations()) { | 
|  | if (breakpoint._uiLocations.size === 0 && breakpoint.enabled()) { | 
|  | return SourcesTestRunner.waitBreakpointSidebarPane(); | 
|  | } | 
|  | } | 
|  | } | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.breakpointsSidebarPaneContent = function() { | 
|  | const paneElement = self.runtime.sharedInstance(Sources.JavaScriptBreakpointsSidebarPane).contentElement; | 
|  | const empty = paneElement.querySelector('.gray-info-message'); | 
|  |  | 
|  | if (empty) { | 
|  | return TestRunner.textContentWithLineBreaks(empty); | 
|  | } | 
|  |  | 
|  | const entries = Array.from(paneElement.querySelectorAll('.breakpoint-entry')); | 
|  | return entries.map(TestRunner.textContentWithLineBreaks).join('\n'); | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.dumpBreakpointSidebarPane = function(title) { | 
|  | TestRunner.addResult('Breakpoint sidebar pane ' + (title || '')); | 
|  | TestRunner.addResult(SourcesTestRunner.breakpointsSidebarPaneContent()); | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.dumpScopeVariablesSidebarPane = function() { | 
|  | TestRunner.addResult('Scope variables sidebar pane:'); | 
|  | const sections = SourcesTestRunner.scopeChainSections(); | 
|  |  | 
|  | SourcesTestRunner.dumpSectionsWithIndent(sections, 0); | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.dumpSectionsWithIndent = function(treeElements, depth) { | 
|  | if (!treeElements || treeElements.length === 0) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | for (const treeElement of treeElements) { | 
|  | const textContent = TestRunner.textContentWithLineBreaks(treeElement.listItemElement); | 
|  | const text = TestRunner.clearSpecificInfoFromStackFrames(textContent); | 
|  | if (text.length > 0) { | 
|  | TestRunner.addResult('    '.repeat(depth) + text); | 
|  | } | 
|  | if (!treeElement.expanded && depth === 0) { | 
|  | TestRunner.addResult('    <section collapsed>'); | 
|  | } | 
|  | SourcesTestRunner.dumpSectionsWithIndent(treeElement.children(), depth + 1); | 
|  | } | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.scopeChainSections = function() { | 
|  | return self.runtime.sharedInstance(Sources.ScopeChainSidebarPane)._treeOutline.rootElement().children(); | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.expandScopeVariablesSidebarPane = function(callback) { | 
|  | const sections = SourcesTestRunner.scopeChainSections(); | 
|  |  | 
|  | for (let i = 0; i < sections.length - 1; ++i) { | 
|  | sections[i].expand(); | 
|  | } | 
|  |  | 
|  | TestRunner.deprecatedRunAfterPendingDispatches(callback); | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.expandProperties = function(properties, callback) { | 
|  | let index = 0; | 
|  |  | 
|  | function expandNextPath() { | 
|  | if (index === properties.length) { | 
|  | TestRunner.safeWrap(callback)(); | 
|  | return; | 
|  | } | 
|  |  | 
|  | const parentTreeElement = properties[index++]; | 
|  | const path = properties[index++]; | 
|  | SourcesTestRunner._expandProperty(parentTreeElement, path, 0, expandNextPath); | 
|  | } | 
|  |  | 
|  | TestRunner.deprecatedRunAfterPendingDispatches(expandNextPath); | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner._expandProperty = function(parentTreeElement, path, pathIndex, callback) { | 
|  | if (pathIndex === path.length) { | 
|  | TestRunner.addResult('Expanded property: ' + path.join('.')); | 
|  | callback(); | 
|  | return; | 
|  | } | 
|  |  | 
|  | const name = path[pathIndex++]; | 
|  | const propertyTreeElement = SourcesTestRunner._findChildPropertyTreeElement(parentTreeElement, name); | 
|  |  | 
|  | if (!propertyTreeElement) { | 
|  | TestRunner.addResult('Failed to expand property: ' + path.slice(0, pathIndex).join('.')); | 
|  | SourcesTestRunner.completeDebuggerTest(); | 
|  | return; | 
|  | } | 
|  |  | 
|  | propertyTreeElement.expand(); | 
|  | TestRunner.deprecatedRunAfterPendingDispatches( | 
|  | SourcesTestRunner._expandProperty.bind(SourcesTestRunner, propertyTreeElement, path, pathIndex, callback)); | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner._findChildPropertyTreeElement = function(parent, childName) { | 
|  | const children = parent.children(); | 
|  |  | 
|  | for (let i = 0; i < children.length; i++) { | 
|  | const treeElement = children[i]; | 
|  | const property = treeElement.property; | 
|  |  | 
|  | if (property.name === childName) { | 
|  | return treeElement; | 
|  | } | 
|  | } | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.setQuiet = function(quiet) { | 
|  | SourcesTestRunner._quiet = quiet; | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.queryScripts = function(filter) { | 
|  | const scripts = TestRunner.debuggerModel.scripts(); | 
|  | return (filter ? scripts.filter(filter) : scripts); | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.createScriptMock = function( | 
|  | url, startLine, startColumn, isContentScript, source, target, preRegisterCallback) { | 
|  | target = target || SDK.targetManager.mainTarget(); | 
|  | const debuggerModel = target.model(SDK.DebuggerModel); | 
|  | const scriptId = ++SourcesTestRunner._lastScriptId + ''; | 
|  | const lineCount = source.computeLineEndings().length; | 
|  | const endLine = startLine + lineCount - 1; | 
|  | const endColumn = | 
|  | (lineCount === 1 ? startColumn + source.length : source.length - source.computeLineEndings()[lineCount - 2]); | 
|  | const hasSourceURL = | 
|  | !!source.match(/\/\/#\ssourceURL=\s*(\S*?)\s*$/m) || !!source.match(/\/\/@\ssourceURL=\s*(\S*?)\s*$/m); | 
|  |  | 
|  | const script = new SDK.Script( | 
|  | debuggerModel, scriptId, url, startLine, startColumn, endLine, endColumn, 0, '', isContentScript, false, | 
|  | undefined, hasSourceURL, source.length); | 
|  |  | 
|  | script.requestContent = function() { | 
|  | const trimmedSource = SDK.Script._trimSourceURLComment(source); | 
|  | return Promise.resolve({content: trimmedSource, isEncoded: false}); | 
|  | }; | 
|  |  | 
|  | if (preRegisterCallback) { | 
|  | preRegisterCallback(script); | 
|  | } | 
|  |  | 
|  | debuggerModel._registerScript(script); | 
|  | return script; | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner._lastScriptId = 0; | 
|  |  | 
|  | SourcesTestRunner.checkRawLocation = function(script, lineNumber, columnNumber, location) { | 
|  | TestRunner.assertEquals(script.scriptId, location.scriptId, 'Incorrect scriptId'); | 
|  | TestRunner.assertEquals(lineNumber, location.lineNumber, 'Incorrect lineNumber'); | 
|  | TestRunner.assertEquals(columnNumber, location.columnNumber, 'Incorrect columnNumber'); | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.checkUILocation = function(uiSourceCode, lineNumber, columnNumber, location) { | 
|  | TestRunner.assertEquals( | 
|  | uiSourceCode, location.uiSourceCode, | 
|  | 'Incorrect uiSourceCode, expected \'' + ((uiSourceCode ? uiSourceCode.url() : null)) + '\',' + | 
|  | ' but got \'' + ((location.uiSourceCode ? location.uiSourceCode.url() : null)) + '\''); | 
|  |  | 
|  | TestRunner.assertEquals( | 
|  | lineNumber, location.lineNumber, | 
|  | 'Incorrect lineNumber, expected \'' + lineNumber + '\', but got \'' + location.lineNumber + '\''); | 
|  |  | 
|  | TestRunner.assertEquals( | 
|  | columnNumber, location.columnNumber, | 
|  | 'Incorrect columnNumber, expected \'' + columnNumber + '\', but got \'' + location.columnNumber + '\''); | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.scriptFormatter = function() { | 
|  | return self.runtime.allInstances(Sources.SourcesView.EditorAction).then(function(editorActions) { | 
|  | for (let i = 0; i < editorActions.length; ++i) { | 
|  | if (editorActions[i] instanceof Sources.ScriptFormatterEditorAction) { | 
|  | return editorActions[i]; | 
|  | } | 
|  | } | 
|  |  | 
|  | return null; | 
|  | }); | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.waitForExecutionContextInTarget = function(target, callback) { | 
|  | const runtimeModel = target.model(SDK.RuntimeModel); | 
|  |  | 
|  | if (runtimeModel.executionContexts().length) { | 
|  | callback(runtimeModel.executionContexts()[0]); | 
|  | return; | 
|  | } | 
|  |  | 
|  | runtimeModel.addEventListener(SDK.RuntimeModel.Events.ExecutionContextCreated, contextCreated); | 
|  |  | 
|  | function contextCreated() { | 
|  | runtimeModel.removeEventListener(SDK.RuntimeModel.Events.ExecutionContextCreated, contextCreated); | 
|  | callback(runtimeModel.executionContexts()[0]); | 
|  | } | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.selectThread = function(target) { | 
|  | UI.context.setFlavor(SDK.Target, target); | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.evaluateOnCurrentCallFrame = function(code) { | 
|  | return TestRunner.debuggerModel.evaluateOnSelectedCallFrame({expression: code, objectGroup: 'console'}); | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.waitDebuggerPluginDecorations = function(sourceFrame) { | 
|  | return TestRunner.addSnifferPromise(Sources.DebuggerPlugin.prototype, '_breakpointDecorationsUpdatedForTest'); | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.waitDebuggerPluginBreakpoints = function(sourceFrame) { | 
|  | return SourcesTestRunner.waitDebuggerPluginDecorations().then(checkIfReady); | 
|  |  | 
|  | function checkIfReady() { | 
|  | for (const {breakpoint} of Bindings.breakpointManager.allBreakpointLocations()) { | 
|  | if (breakpoint._uiLocations.size === 0 && breakpoint.enabled()) { | 
|  | return SourcesTestRunner.waitDebuggerPluginDecorations().then(checkIfReady); | 
|  | } | 
|  | } | 
|  |  | 
|  | return Promise.resolve(); | 
|  | } | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.dumpDebuggerPluginBreakpoints = function(sourceFrame) { | 
|  | const textEditor = sourceFrame._textEditor; | 
|  |  | 
|  | for (let lineNumber = 0; lineNumber < textEditor.linesCount; ++lineNumber) { | 
|  | if (!textEditor.hasLineClass(lineNumber, 'cm-breakpoint')) { | 
|  | continue; | 
|  | } | 
|  |  | 
|  | const disabled = textEditor.hasLineClass(lineNumber, 'cm-breakpoint-disabled'); | 
|  | const conditional = textEditor.hasLineClass(lineNumber, 'cm-breakpoint-conditional'); | 
|  | TestRunner.addResult( | 
|  | 'breakpoint at ' + lineNumber + ((disabled ? ' disabled' : '')) + ((conditional ? ' conditional' : ''))); | 
|  | const range = new TextUtils.TextRange(lineNumber, 0, lineNumber, textEditor.line(lineNumber).length); | 
|  | let bookmarks = textEditor.bookmarks(range, Sources.DebuggerPlugin.BreakpointDecoration._bookmarkSymbol); | 
|  | bookmarks = bookmarks.filter(bookmark => !!bookmark.position()); | 
|  | bookmarks.sort((bookmark1, bookmark2) => bookmark1.position().startColumn - bookmark2.position().startColumn); | 
|  |  | 
|  | for (const bookmark of bookmarks) { | 
|  | const position = bookmark.position(); | 
|  | const element = bookmark[Sources.DebuggerPlugin.BreakpointDecoration._elementSymbolForTest]; | 
|  | const disabled = element.classList.contains('cm-inline-disabled'); | 
|  | const conditional = element.classList.contains('cm-inline-conditional'); | 
|  |  | 
|  | TestRunner.addResult( | 
|  | '  inline breakpoint at (' + position.startLine + ', ' + position.startColumn + ')' + | 
|  | ((disabled ? ' disabled' : '')) + ((conditional ? ' conditional' : ''))); | 
|  | } | 
|  | } | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.clickDebuggerPluginBreakpoint = function(sourceFrame, lineNumber, index, next) { | 
|  | const textEditor = sourceFrame._textEditor; | 
|  | const lineLength = textEditor.line(lineNumber).length; | 
|  | const lineRange = new TextUtils.TextRange(lineNumber, 0, lineNumber, lineLength); | 
|  | const bookmarks = textEditor.bookmarks(lineRange, Sources.DebuggerPlugin.BreakpointDecoration._bookmarkSymbol); | 
|  | bookmarks.sort((bookmark1, bookmark2) => bookmark1.position().startColumn - bookmark2.position().startColumn); | 
|  | const bookmark = bookmarks[index]; | 
|  |  | 
|  | if (bookmark) { | 
|  | bookmark[Sources.DebuggerPlugin.BreakpointDecoration._elementSymbolForTest].click(); | 
|  | } else { | 
|  | TestRunner.addResult(`Could not click on Javascript breakpoint - lineNumber: ${lineNumber}, index: ${index}`); | 
|  | next(); | 
|  | } | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.debuggerPlugin = function(sourceFrame) { | 
|  | return sourceFrame._plugins.find(plugin => plugin instanceof Sources.DebuggerPlugin); | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.waitUntilDebuggerPluginLoaded = async function(sourceFrame) { | 
|  | while (!SourcesTestRunner.debuggerPlugin(sourceFrame)) { | 
|  | await TestRunner.addSnifferPromise(sourceFrame, '_ensurePluginsLoaded'); | 
|  | } | 
|  | return SourcesTestRunner.debuggerPlugin(sourceFrame); | 
|  | }; | 
|  |  | 
|  | SourcesTestRunner.setEventListenerBreakpoint = function(id, enabled, targetName) { | 
|  | const pane = self.runtime.sharedInstance(BrowserDebugger.EventListenerBreakpointsSidebarPane); | 
|  |  | 
|  | const auxData = {'eventName': id}; | 
|  |  | 
|  | if (targetName) { | 
|  | auxData.targetName = targetName; | 
|  | } | 
|  |  | 
|  | const breakpoint = SDK.domDebuggerManager.resolveEventListenerBreakpoint(auxData); | 
|  |  | 
|  | if (breakpoint.enabled() !== enabled) { | 
|  | pane._breakpoints.get(breakpoint).checkbox.checked = enabled; | 
|  | pane._breakpointCheckboxClicked(breakpoint); | 
|  | } | 
|  | }; | 
|  |  | 
|  | TestRunner.deprecatedInitAsync(` | 
|  | function scheduleTestFunction() { | 
|  | setTimeout(testFunction, 0); | 
|  | } | 
|  | `); |