| // 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); |
| } |
| `); |