From ffa35196751766028feb7cda38cf4d43ead2a6f7 Mon Sep 17 00:00:00 2001 From: Craig Nishina Date: Fri, 30 Nov 2018 18:48:12 -0800 Subject: [PATCH] chore(debugger): remove debugger and explore methods (#5070) --- lib/browser.ts | 121 +------------ lib/debugger.ts | 280 ----------------------------- lib/debugger/clients/explorer.js | 157 ---------------- lib/debugger/clients/wddebugger.js | 83 --------- lib/debugger/debuggerCommons.js | 113 ------------ lib/debugger/modes/commandRepl.js | 127 ------------- lib/debugger/modes/debuggerRepl.js | 143 --------------- lib/frameworks/debugprint.js | 2 +- 8 files changed, 2 insertions(+), 1024 deletions(-) delete mode 100644 lib/debugger.ts delete mode 100644 lib/debugger/clients/explorer.js delete mode 100644 lib/debugger/clients/wddebugger.js delete mode 100644 lib/debugger/debuggerCommons.js delete mode 100644 lib/debugger/modes/commandRepl.js delete mode 100644 lib/debugger/modes/debuggerRepl.js diff --git a/lib/browser.ts b/lib/browser.ts index 1966487c9..009781ec0 100644 --- a/lib/browser.ts +++ b/lib/browser.ts @@ -1,9 +1,8 @@ import {BPClient} from 'blocking-proxy'; -import {ActionSequence, By, Capabilities, Command as WdCommand, FileDetector, ICommandName, Navigation, Options, promise as wdpromise, Session, TargetLocator, TouchSequence, until, WebDriver, WebElement, WebElementPromise} from 'selenium-webdriver'; +import {By, Command as WdCommand, ICommandName, Navigation, promise as wdpromise, Session, WebDriver, WebElement, WebElementPromise} from 'selenium-webdriver'; import * as url from 'url'; import {extend as extendWD, ExtendedWebDriver} from 'webdriver-js-extender'; -import {DebugHelper} from './debugger'; import {build$, build$$, ElementArrayFinder, ElementFinder} from './element'; import {IError} from './exitCodes'; import {ProtractorExpectedConditions} from './expectedConditions'; @@ -309,11 +308,6 @@ export class ProtractorBrowser extends AbstractExtendedWebDriver { */ ng12Hybrid: boolean; - /** - * A helper that manages debugging tests. - */ - debugHelper: DebugHelper; - // This index type allows looking up methods by name so we can do mixins. [key: string]: any; @@ -358,7 +352,6 @@ export class ProtractorBrowser extends AbstractExtendedWebDriver { this.getPageTimeout = DEFAULT_GET_PAGE_TIMEOUT; this.params = {}; this.resetUrl = DEFAULT_RESET_URL; - this.debugHelper = new DebugHelper(this); let ng12Hybrid_ = false; Object.defineProperty(this, 'ng12Hybrid', { @@ -1038,118 +1031,6 @@ export class ProtractorBrowser extends AbstractExtendedWebDriver { clientSideScripts.getLocationAbsUrl, 'Protractor.getLocationAbsUrl()', rootEl)); } - /** - * Adds a task to the control flow to pause the test and inject helper - * functions - * into the browser, so that debugging may be done in the browser console. - * - * This should be used under node in debug mode, i.e. with - * protractor debug - * - * @example - * While in the debugger, commands can be scheduled through webdriver by - * entering the repl: - * debug> repl - * > element(by.input('user')).sendKeys('Laura'); - * > browser.debugger(); - * Press Ctrl + c to leave debug repl - * debug> c - * - * This will run the sendKeys command as the next task, then re-enter the - * debugger. - */ - debugger() { - // jshint debug: true - return this.driver.executeScript(clientSideScripts.installInBrowser) - .then(() => wdpromise.controlFlow().execute(() => { - debugger; - }, 'add breakpoint to control flow')); - } - - /** - * See browser.explore(). - */ - enterRepl(opt_debugPort?: number) { - return this.explore(opt_debugPort); - } - - /** - * Beta (unstable) explore function for entering the repl loop from - * any point in the control flow. Use browser.explore() in your test. - * Does not require changes to the command line (no need to add 'debug'). - * Note, if you are wrapping your own instance of Protractor, you must - * expose globals 'browser' and 'protractor' for pause to work. - * - * @example - * element(by.id('foo')).click(); - * browser.explore(); - * // Execution will stop before the next click action. - * element(by.id('bar')).click(); - * - * @param {number=} opt_debugPort Optional port to use for the debugging - * process - */ - explore(opt_debugPort?: number) { - let debuggerClientPath = __dirname + '/debugger/clients/explorer.js'; - let onStartFn = (firstTime: boolean) => { - logger.info(); - if (firstTime) { - logger.info('------- Element Explorer -------'); - logger.info( - 'Starting WebDriver debugger in a child process. Element ' + - 'Explorer is still beta, please report issues at ' + - 'github.com/angular/protractor'); - logger.info(); - logger.info('Type to see a list of locator strategies.'); - logger.info('Use the `list` helper function to find elements by strategy:'); - logger.info(' e.g., list(by.binding(\'\')) gets all bindings.'); - logger.info(); - } - }; - this.debugHelper.initBlocking(debuggerClientPath, onStartFn, opt_debugPort); - } - - /** - * Beta (unstable) pause function for debugging webdriver tests. Use - * browser.pause() in your test to enter the protractor debugger from that - * point in the control flow. - * Does not require changes to the command line (no need to add 'debug'). - * Note, if you are wrapping your own instance of Protractor, you must - * expose globals 'browser' and 'protractor' for pause to work. - * - * @example - * element(by.id('foo')).click(); - * browser.pause(); - * // Execution will stop before the next click action. - * element(by.id('bar')).click(); - * - * @param {number=} opt_debugPort Optional port to use for the debugging - * process - */ - pause(opt_debugPort?: number): wdpromise.Promise { - if (this.debugHelper.isAttached()) { - logger.info('Encountered browser.pause(), but debugger already attached.'); - return wdpromise.when(true); - } - let debuggerClientPath = __dirname + '/debugger/clients/wddebugger.js'; - let onStartFn = (firstTime: boolean) => { - logger.info(); - logger.info('Encountered browser.pause(). Attaching debugger...'); - if (firstTime) { - logger.info(); - logger.info('------- WebDriver Debugger -------'); - logger.info( - 'Starting WebDriver debugger in a child process. Pause is ' + - 'still beta, please report issues at github.com/angular/protractor'); - logger.info(); - logger.info('press c to continue to the next webdriver command'); - logger.info('press ^D to detach debugger and resume code execution'); - logger.info(); - } - }; - this.debugHelper.init(debuggerClientPath, onStartFn, opt_debugPort); - } - /** * Determine if the control flow is enabled. * diff --git a/lib/debugger.ts b/lib/debugger.ts deleted file mode 100644 index b22cfa0dd..000000000 --- a/lib/debugger.ts +++ /dev/null @@ -1,280 +0,0 @@ -import * as net from 'net'; -import {promise as wdpromise, WebElement} from 'selenium-webdriver'; -import * as util from 'util'; - -import {ProtractorBrowser} from './browser'; -import {Locator} from './locators'; -import {Logger} from './logger'; -import {Ptor} from './ptor'; -import * as helper from './util'; -let breakpointHook = require('./breakpointhook.js'); - -declare var global: any; -declare var process: any; - -let logger = new Logger('protractor'); - -export class DebugHelper { - /** - * Set to true when we validate that the debug port is open. Since the debug - * port is held open forever once the debugger is attached, it's important - * we only do validation once. - */ - debuggerValidated_: boolean; - - dbgCodeExecutor: any; - - constructor(private browserUnderDebug_: ProtractorBrowser) {} - - - initBlocking(debuggerClientPath: string, onStartFn: Function, opt_debugPort?: number) { - this.init_(debuggerClientPath, true, onStartFn, opt_debugPort); - } - - init(debuggerClientPath: string, onStartFn: Function, opt_debugPort?: number) { - this.init_(debuggerClientPath, false, onStartFn, opt_debugPort); - } - - /** - * 1) Set up helper functions for debugger clients to call on (e.g. - * execute code, get autocompletion). - * 2) Enter process into debugger mode. (i.e. process._debugProcess). - * 3) Invoke the debugger client specified by debuggerClientPath. - * - * @param {string} debuggerClientPath Absolute path of debugger client to use. - * @param {boolean} blockUntilExit Whether to block the flow until process exit or resume - * immediately. - * @param {Function} onStartFn Function to call when the debugger starts. The - * function takes a single parameter, which represents whether this is the - * first time that the debugger is called. - * @param {number=} opt_debugPort Optional port to use for the debugging - * process. - * - * @return {Promise} If blockUntilExit, a promise resolved when the debugger process - * exits. Otherwise, resolved when the debugger process is ready to begin. - */ - init_( - debuggerClientPath: string, blockUntilExit: boolean, onStartFn: Function, - opt_debugPort?: number) { - const vm_ = require('vm'); - let flow = wdpromise.controlFlow(); - - interface Context { - require: any; - [key: string]: any; - } - let context: Context = {require: require}; - global.list = (locator: Locator) => { - return (global.protractor).browser.findElements(locator).then((arr: WebElement[]) => { - let found: string[] = []; - for (let i = 0; i < arr.length; ++i) { - arr[i].getText().then((text: string) => { - found.push(text); - }); - } - return found; - }); - }; - for (let key in global) { - context[key] = global[key]; - } - let sandbox = vm_.createContext(context); - - let debuggingDone = wdpromise.defer(); - - // We run one flow.execute block for the debugging session. All - // subcommands should be scheduled under this task. - let executePromise = flow.execute(() => { - process['debugPort'] = opt_debugPort || process['debugPort']; - this.validatePortAvailability_(process['debugPort']).then((firstTime: boolean) => { - onStartFn(firstTime); - - let args = [process.pid, process['debugPort']]; - if (this.browserUnderDebug_.debuggerServerPort) { - args.push(this.browserUnderDebug_.debuggerServerPort); - } - let nodedebug = require('child_process').fork(debuggerClientPath, args); - process.on('exit', function() { - nodedebug.kill('SIGTERM'); - }); - nodedebug - .on('message', - (m: string) => { - if (m === 'ready') { - breakpointHook(); - if (!blockUntilExit) { - debuggingDone.fulfill(); - } - } - }) - .on('exit', () => { - // Clear this so that we know it's ok to attach a debugger - // again. - this.dbgCodeExecutor = null; - debuggingDone.fulfill(); - }); - }); - return debuggingDone.promise; - }, 'debugging tasks'); - - // Helper used only by debuggers at './debugger/modes/*.js' to insert code - // into the control flow, via debugger 'evaluate' protocol. - // In order to achieve this, we maintain a task at the top of the control - // flow, so that we can insert frames into it. - // To be able to simulate callback/asynchronous code, we poll this object - // whenever `breakpointHook` is called. - this.dbgCodeExecutor = { - execPromise_: undefined, // Promise pointing to currently executing command. - execPromiseResult_: undefined, // Return value of promise. - execPromiseError_: undefined, // Error from promise. - - // A dummy repl server to make use of its completion function. - replServer_: require('repl').start({ - input: {on: function() {}, resume: function() {}}, - // dummy readable stream - output: {write: function() {}}, // dummy writable stream - useGlobal: true - }), - - // Execute a function, which could yield a value or a promise, - // and allow its result to be accessed synchronously - execute_: function(execFn_: Function) { - this.execPromiseResult_ = this.execPromiseError_ = undefined; - - this.execPromise_ = execFn_(); - // Note: This needs to be added after setting execPromise to execFn, - // or else we cause this.execPromise_ to get stuck in pending mode - // at our next breakpoint. - this.execPromise_.then( - (result: Object) => { - this.execPromiseResult_ = result; - breakpointHook(); - }, - (err: Error) => { - this.execPromiseError_ = err; - breakpointHook(); - }); - }, - - // Execute a piece of code. - // Result is a string representation of the evaluation. - execute: function(code: Function) { - let execFn_ = () => { - // Run code through vm so that we can maintain a local scope which is - // isolated from the rest of the execution. - let res: wdpromise.Promise; - try { - res = vm_.runInContext(code, sandbox); - } catch (e) { - res = wdpromise.when('Error while evaluating command: ' + e); - } - if (!wdpromise.isPromise(res)) { - res = wdpromise.when(res); - } - - return res.then((res: any) => { - if (res === undefined) { - return undefined; - } else { - // The '' forces res to be expanded into a string instead of just - // '[Object]'. Then we remove the extra space caused by the '' - // using substring. - return util.format.apply(this, ['', res]).substring(1); - } - }); - }; - this.execute_(execFn_); - }, - - // Autocomplete for a line. - // Result is a JSON representation of the autocomplete response. - complete: function(line: string) { - let execFn_ = () => { - let deferred = wdpromise.defer(); - this.replServer_.complete(line, (err: any, res: any) => { - if (err) { - deferred.reject(err); - } else { - deferred.fulfill(JSON.stringify(res)); - } - }); - return deferred.promise; - }; - this.execute_(execFn_); - }, - - // Code finished executing. - resultReady: function() { - return !(this.execPromise_.state_ === 'pending'); - }, - - // Get asynchronous results synchronously. - // This will throw if result is not ready. - getResult: function() { - if (!this.resultReady()) { - throw new Error('Result not ready'); - } - if (this.execPromiseError_) { - throw this.execPromiseError_; - } - return this.execPromiseResult_; - } - }; - - return executePromise; - } - - /** - * Validates that the port is free to use. This will only validate the first - * time it is called. The reason is that on subsequent calls, the port will - * already be bound to the debugger, so it will not be available, but that is - * okay. - * - * @returns {Promise} A promise that becomes ready when the - * validation - * is done. The promise will resolve to a boolean which represents whether - * this is the first time that the debugger is called. - */ - private validatePortAvailability_(port: number): wdpromise.Promise { - if (this.debuggerValidated_) { - return wdpromise.when(false); - } - - let doneDeferred = wdpromise.defer(); - - // Resolve doneDeferred if port is available. - let tester = net.connect({port: port}, () => { - doneDeferred.reject( - 'Port ' + port + ' is already in use. Please specify ' + - 'another port to debug.'); - }); - tester.once('error', (err: NodeJS.ErrnoException) => { - if (err.code === 'ECONNREFUSED') { - tester - .once( - 'close', - () => { - doneDeferred.fulfill(true); - }) - .end(); - } else { - doneDeferred.reject( - 'Unexpected failure testing for port ' + port + ': ' + JSON.stringify(err)); - } - }); - - return doneDeferred.promise.then( - (firstTime: boolean) => { - this.debuggerValidated_ = true; - return firstTime; - }, - (err: string) => { - console.error(err); - return process.exit(1) as never; - }); - } - - public isAttached(): boolean { - return !!this.dbgCodeExecutor; - } -} diff --git a/lib/debugger/clients/explorer.js b/lib/debugger/clients/explorer.js deleted file mode 100644 index b0dee20c2..000000000 --- a/lib/debugger/clients/explorer.js +++ /dev/null @@ -1,157 +0,0 @@ -var repl = require('repl'); -var debuggerCommons = require('../debuggerCommons'); -var CommandRepl = require('../modes/commandRepl'); - -/** - * BETA BETA BETA - * Custom explorer to test protractor commands. - * - * @constructor - */ -var WdRepl = function() { - this.client; -}; - -/** - * Instantiate a server to handle IO. - * @param {number} port The port to start the server. - * @private - */ -WdRepl.prototype.initServer_ = function(port) { - var net = require('net'); - var self = this; - var cmdRepl = new CommandRepl(this.client); - - var received = ''; - net.createServer(function(sock) { - sock.on('data', function(data) { - received += data.toString(); - var eolIndex = received.indexOf('\r\n'); - if (eolIndex === 0) { - return; - } - var input = received.substring(0, eolIndex); - received = received.substring(eolIndex + 2); - if (data[0] === 0x1D) { - // '^]': term command - self.client.req({command: 'disconnect'}, function() { - // Intentionally blank. - }); - sock.end(); - // TODO(juliemr): Investigate why this is necessary. At this point, there - // should be no active listeners so this process should just exit - // by itself. - process.exit(0); - } else if (input[input.length - 1] === '\t') { - // If the last character is the TAB key, this is an autocomplete - // request. We use everything before the TAB as the init data to feed - // into autocomplete. - input = input.substring(0, input.length - 1); - cmdRepl.complete(input, function(err, res) { - if (err) { - sock.write('ERROR: ' + err + '\r\n'); - } else { - sock.write(JSON.stringify(res) + '\r\n'); - } - }); - } else { - // Normal input - input = input.trim(); - cmdRepl.stepEval(input, function(err, res) { - if (err) { - sock.write('ERROR: ' + err + '\r\n'); - return; - } - if (res === undefined) { - res = ''; - } - sock.write(res + '\r\n'); - }); - } - }); - }).listen(port); - - console.log('Server listening on 127.0.0.1:' + port); -}; - -/** - * Instantiate a repl to handle IO. - * @private - */ -WdRepl.prototype.initRepl_ = function() { - var self = this; - var cmdRepl = new CommandRepl(this.client); - - // Eval function for processing a single step in repl. - var stepEval = function(cmd, context, filename, callback) { - // The command that eval feeds is of the form '(CMD\n)', so we trim the - // double quotes and new line. - cmd = debuggerCommons.trimReplCmd(cmd); - cmdRepl.stepEval(cmd, function(err, res) { - // Result is a string representation of the evaluation. - if (res !== undefined) { - console.log(res); - } - callback(err, undefined); - }); - }; - - var replServer = repl.start({ - prompt: cmdRepl.prompt, - input: process.stdin, - output: process.stdout, - eval: stepEval, - useGlobal: false, - ignoreUndefined: true, - completer: cmdRepl.complete.bind(cmdRepl) - }); - - replServer.on('exit', function() { - console.log('Element Explorer Exiting...'); - self.client.req({command: 'disconnect'}, function() { - // TODO(juliemr): Investigate why this is necessary. At this point, there - // should be no active listeners so this process should just exit - // by itself. - process.exit(0); - }); - }); -}; - -/** - * Instantiate a repl or a server. - * @private - */ -WdRepl.prototype.initReplOrServer_ = function() { - // Note instead of starting either repl or server, another approach is to - // feed the server socket into the repl as the input/output streams. The - // advantage is that the process becomes much more realistic because now we're - // using the normal repl. However, it was not possible to test autocomplete - // this way since we cannot immitate the TAB key over the wire. - var debuggerServerPort = process.argv[4]; - if (debuggerServerPort) { - this.initServer_(debuggerServerPort); - } else { - this.initRepl_(); - } -}; - -/** - * Initiate the debugger. - * @public - */ -WdRepl.prototype.init = function() { - var self = this; - this.client = debuggerCommons.attachDebugger(process.argv[2], process.argv[3]); - this.client.once('ready', function() { - debuggerCommons.setEvaluateBreakpoint(self.client, function() { - process.send('ready'); - self.client.reqContinue(function() { - // Intentionally blank. - }); - }); - self.initReplOrServer_(); - }); -}; - -var wdRepl = new WdRepl(); -wdRepl.init(); diff --git a/lib/debugger/clients/wddebugger.js b/lib/debugger/clients/wddebugger.js deleted file mode 100644 index f082e376d..000000000 --- a/lib/debugger/clients/wddebugger.js +++ /dev/null @@ -1,83 +0,0 @@ -var repl = require('repl'); -var debuggerCommons = require('../debuggerCommons'); -var DebuggerRepl = require('../modes/debuggerRepl'); - -/** - * Custom protractor debugger which steps through one control flow task at a time. - * - * @constructor - */ -var WdDebugger = function() { - this.client; - this.replServer; - this.dbgRepl; -}; - -/** - * Eval function for processing a single step in repl. - * @private - * @param {string} cmd - * @param {object} context - * @param {string} filename - * @param {function} callback - */ -WdDebugger.prototype.stepEval_ = function(cmd, context, filename, callback) { - // The loop won't come back until 'callback' is called. - // Note - node's debugger gets around this by adding custom objects - // named 'c', 's', etc to the REPL context. They have getters which - // perform the desired function, and the callback is stored for later use. - // Think about whether this is a better pattern. - - cmd = debuggerCommons.trimReplCmd(cmd); - this.dbgRepl.stepEval(cmd, callback); -}; - -/** - * Instantiate all repl objects, and debuggerRepl as current and start repl. - * @private - */ -WdDebugger.prototype.initRepl_ = function() { - var self = this; - this.dbgRepl = new DebuggerRepl(this.client); - - // We want the prompt to show up only after the controlflow text prints. - this.dbgRepl.printControlFlow_(function() { - self.replServer = repl.start({ - prompt: self.dbgRepl.prompt, - input: process.stdin, - output: process.stdout, - eval: self.stepEval_.bind(self), - useGlobal: false, - ignoreUndefined: true, - completer: self.dbgRepl.complete.bind(self.dbgRepl) - }); - - self.replServer.on('exit', function() { - console.log('Resuming code execution'); - self.client.req({command: 'disconnect'}, function() { - process.exit(); - }); - }); - }); -}; - -/** - * Initiate the debugger. - * @public - */ -WdDebugger.prototype.init = function() { - var self = this; - this.client = debuggerCommons.attachDebugger(process.argv[2], process.argv[3]); - this.client.once('ready', function() { - debuggerCommons.setWebDriverCommandBreakpoint(self.client, function() { - process.send('ready'); - self.client.reqContinue(function() { - // Intentionally blank. - }); - }); - self.initRepl_(); - }); -}; - -var wdDebugger = new WdDebugger(); -wdDebugger.init(); diff --git a/lib/debugger/debuggerCommons.js b/lib/debugger/debuggerCommons.js deleted file mode 100644 index f7b3b7833..000000000 --- a/lib/debugger/debuggerCommons.js +++ /dev/null @@ -1,113 +0,0 @@ -var baseDebugger; -try { - baseDebugger = require('_debugger'); -} catch (e) { - if (e.code == 'MODULE_NOT_FOUND') { - console.log('***********************************************************'); - console.log('* WARNING: _debugger module not available on Node.js 8 *'); - console.log('* and higher. *'); - console.log('* *'); - console.log('* Use \'debugger\' keyword instead: *'); - console.log('* https://goo.gl/MvWqFh *'); - console.log('***********************************************************'); - } - throw e; -} -var path = require('path'); - -/** - * Create a debugger client and attach to a running protractor process. - * @param {number} pid Pid of the process to attach the debugger to. - * @param {number=} opt_port Port to set up the debugger connection over. - * @return {!baseDebugger.Client} The connected debugger client. - */ -exports.attachDebugger = function(pid, opt_port) { - var client = new baseDebugger.Client(); - var port = opt_port || process.debugPort; - - // Call this private function instead of sending SIGUSR1 because Windows. - process._debugProcess(pid); - - // Connect to debugger on port with retry 200ms apart. - var connectWithRetry = function(attempts) { - client.connect(port, 'localhost') - .on('error', function(e) { - if (attempts === 1) { - throw e; - } else { - setTimeout(function() { - connectWithRetry(attempts - 1); - }, 200); - } - }); - }; - connectWithRetry(10); - - return client; -}; - - -/** - * Set a breakpoint for evaluating REPL statements. - * This sets a breakpoint in Protractor's breakpointhook.js, so that we'll - * break after executing a command from the REPL. - */ -exports.setEvaluateBreakpoint = function(client, cb) { - client.setBreakpoint({ - type: 'scriptRegExp', - target: prepareDebuggerPath('built', 'breakpointhook.js'), - line: 2 - }, function(err, response) { - if (err) { - throw new Error(err); - } - cb(response.breakpoint); - }); -}; - -/** - * Set a breakpoint for moving forward by one webdriver command. - * This sets a breakpoint in selenium-webdriver/lib/http.js, and is - * extremely sensitive to the selenium version. It works for - * selenium-webdriver 3.0.1 - * This breaks on the following line in http.js: - * let request = buildRequest(this.customCommands_, this.w3c, command); - * And will need to break at a similar point in future selenium-webdriver - * versions. - */ -exports.setWebDriverCommandBreakpoint = function(client, cb) { - client.setBreakpoint({ - type: 'scriptRegExp', - target: prepareDebuggerPath('lib', 'http.js'), - line: 433 - }, function(err, response) { - if (err) { - throw new Error(err); - } - cb(response.breakpoint); - }); -}; - -/** - * Create a cross-platform friendly path for setting scriptRegExp breakpoints. - */ -function prepareDebuggerPath(...parts) { - return path.join(...parts) - .replace('\\', '\\\\') - .replace('.', '\\.'); -} - -/** - * Trim excess symbols from the repl command so that it is consistent with - * the user input. - * @param {string} cmd Cmd provided by the repl server. - * @return {string} The trimmed cmd. - */ -exports.trimReplCmd = function(cmd) { - // Given user input 'foobar', some versions of node provide '(foobar\n)', - // while other versions of node provide 'foobar\n'. - if (cmd.length >= 2 && cmd[0] === '(' && cmd[cmd.length - 1] === ')') { - cmd = cmd.substring(1, cmd.length - 1); - } - return cmd.slice(0, cmd.length - 1); -}; diff --git a/lib/debugger/modes/commandRepl.js b/lib/debugger/modes/commandRepl.js deleted file mode 100644 index 6608e5970..000000000 --- a/lib/debugger/modes/commandRepl.js +++ /dev/null @@ -1,127 +0,0 @@ -var REPL_INITIAL_SUGGESTIONS = [ - 'element(by.id(\'\'))', - 'element(by.css(\'\'))', - 'element(by.name(\'\'))', - 'element(by.binding(\'\'))', - 'element(by.xpath(\'\'))', - 'element(by.tagName(\'\'))', - 'element(by.className(\'\'))' -]; - -/** - * Repl to interactively run commands in the context of the test. - * - * @param {Client} node debugger client. - * @constructor - */ -var CommandRepl = function(client) { - this.client = client; - this.prompt = '> '; -}; - -/** - * Eval function for processing a single step in repl. - * Call callback with the result when complete. - * - * @public - * @param {string} expression - * @param {function} callback - */ -CommandRepl.prototype.stepEval = function(expression, callback) { - expression = expression.replace(/"/g, '\\\"'); - - var expr = 'browser.debugHelper.dbgCodeExecutor.execute("' + expression + '")'; - this.evaluate_(expr, callback); -}; - -/** - * Autocomplete user entries. - * Call callback with the suggestions. - * - * @public - * @param {string} line Initial user entry - * @param {function} callback - */ -CommandRepl.prototype.complete = function(line, callback) { - if (line === '') { - callback(null, [REPL_INITIAL_SUGGESTIONS, '']); - } else { - // TODO(juliemr): This is freezing the program! - line = line.replace(/"/g, '\\\"'); - var expr = 'browser.debugHelper.dbgCodeExecutor.complete("' + line + '")'; - this.evaluate_(expr, function(err, res) { - // Result is a JSON representation of the autocomplete response. - var result = res === undefined ? undefined : JSON.parse(res); - callback(err, result); - }); - } -}; - -/** - * Helper function to evaluate an expression remotely, and callback with - * the result. The expression can be a promise, in which case, the method - * will wait for the result and callback with the resolved value. - * - * @private - * @param {string} expression Expression to evaluate - * @param {function} callback - */ -CommandRepl.prototype.evaluate_ = function(expression, callback) { - var self = this; - var onbreak_ = function() { - self.client.req({ - command: 'evaluate', - arguments: { - frame: 0, - maxStringLength: 1000, - expression: 'browser.debugHelper.dbgCodeExecutor.resultReady()' - } - }, function(err, res) { - if (err) { - throw new Error('Error while checking if debugger expression result was ready.' + - 'Expression: ' + expression + ' Error: ' + err); - } - // If code finished executing, get result. - if (res.value) { - self.client.req({ - command: 'evaluate', - arguments: { - frame: 0, - maxStringLength: -1, - expression: 'browser.debugHelper.dbgCodeExecutor.getResult()' - } - }, function(err, res) { - try { - callback(err, res.value); - } catch (e) { - callback(e, undefined); - } - self.client.removeListener('break', onbreak_); - }); - } else { - // If we need more loops for the code to finish executing, continue - // until the next execute step. - self.client.reqContinue(function() { - // Intentionally blank. - }); - } - }); - }; - - this.client.on('break', onbreak_); - - this.client.req({ - command: 'evaluate', - arguments: { - frame: 0, - maxStringLength: 1000, - expression: expression - } - }, function() { - self.client.reqContinue(function() { - // Intentionally blank. - }); - }); -}; - -module.exports = CommandRepl; diff --git a/lib/debugger/modes/debuggerRepl.js b/lib/debugger/modes/debuggerRepl.js deleted file mode 100644 index 0d1c46266..000000000 --- a/lib/debugger/modes/debuggerRepl.js +++ /dev/null @@ -1,143 +0,0 @@ -var util = require('util'); - -var DBG_INITIAL_SUGGESTIONS = - ['repl', 'c', 'frame', 'scopes', 'scripts', 'source', 'backtrace']; - -/** - * Repl to step through webdriver test code. - * - * @param {Client} node debugger client. - * @constructor - */ -var DebuggerRepl = function(client) { - this.client = client; - this.prompt = '>>> '; -}; - -/** - * Eval function for processing a single step in repl. - * Call callback with the result when complete. - * - * @public - * @param {string} cmd - * @param {function} callback - */ -DebuggerRepl.prototype.stepEval = function(cmd, callback) { - switch (cmd) { - case 'c': - this.printNextStep_(callback); - this.client.reqContinue(function() { - // Intentionally blank. - }); - break; - case 'repl': - console.log('Error: using repl from browser.pause() has been removed. ' + - 'Please use browser.enterRepl instead.'); - callback(); - break; - case 'schedule': - this.printControlFlow_(callback); - break; - case 'frame': - this.client.req({command: 'frame'}, function(err, res) { - console.log(util.inspect(res, {colors: true})); - callback(); - }); - break; - case 'scopes': - this.client.req({command: 'scopes'}, function(err, res) { - console.log(util.inspect(res, {depth: 4, colors: true})); - callback(); - }); - break; - case 'scripts': - this.client.req({command: 'scripts'}, function(err, res) { - console.log(util.inspect(res, {depth: 4, colors: true})); - callback(); - }); - break; - case 'source': - this.client.req({command: 'source'}, function(err, res) { - console.log(util.inspect(res, {depth: 4, colors: true})); - callback(); - }); - break; - case 'backtrace': - this.client.req({command: 'backtrace'}, function(err, res) { - console.log(util.inspect(res, {depth: 4, colors: true})); - callback(); - }); - break; - default: - console.log('Unrecognized command.'); - callback(); - break; - } -}; - -/** - * Autocomplete user entries. - * Call callback with the suggestions. - * - * @public - * @param {string} line Initial user entry - * @param {function} callback - */ -DebuggerRepl.prototype.complete = function(line, callback) { - var suggestions = DBG_INITIAL_SUGGESTIONS.filter(function(suggestion) { - return suggestion.indexOf(line) === 0; - }); - console.log('suggestions'); - callback(null, [suggestions, line]); -}; - -/** - * Print the next command and setup the next breakpoint. - * - * @private - * @param {function} callback - */ -DebuggerRepl.prototype.printNextStep_ = function(callback) { - var self = this; - var onBreak_ = function() { - self.client.req({ - command: 'evaluate', - arguments: { - frame: 0, - maxStringLength: 1000, - expression: 'command.getName()' - } - }, function(err, res) { - // We ignore errors here because we'll get one from the initial break. - if (res.value) { - console.log('-- Next command: ' + res.value); - } - callback(); - }); - }; - this.client.once('break', onBreak_); -}; - -/** - * Print the controlflow. - * - * @private - * @param {function} callback - */ -DebuggerRepl.prototype.printControlFlow_ = function(callback) { - this.client.req({ - command: 'evaluate', - arguments: { - frame: 0, - maxStringLength: 4000, - expression: 'protractor.promise.controlFlow().getSchedule()' - } - }, function(err, controlFlowResponse) { - if (controlFlowResponse.value) { - console.log(controlFlowResponse.value); - } - callback(); - }); -}; - -module.exports = DebuggerRepl; diff --git a/lib/frameworks/debugprint.js b/lib/frameworks/debugprint.js index 8b10c353a..0aaaa846a 100644 --- a/lib/frameworks/debugprint.js +++ b/lib/frameworks/debugprint.js @@ -18,4 +18,4 @@ exports.run = (runner, specs) => { failedCount: 0 }); }); -}; +}; \ No newline at end of file