Skip to content
This repository was archived by the owner on Jul 29, 2024. It is now read-only.

Commit 99a8127

Browse files
committed
experimental(debugger): make element explorer work with node 0.12.0
Node has changed its debugger significantly in 0.12.0, and these changes are necessary to get it to work now.
1 parent 29ce5c6 commit 99a8127

File tree

4 files changed

+100
-57
lines changed

4 files changed

+100
-57
lines changed

lib/debugger/clients/explorer.js

+5-17
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
var repl = require('repl');
2-
var baseDebugger = require('_debugger');
2+
var debuggerCommons = require('../debuggerCommons');
33
var CommandRepl = require('../modes/commandRepl');
44

55
/**
@@ -9,7 +9,7 @@ var CommandRepl = require('../modes/commandRepl');
99
* @constructor
1010
*/
1111
var WdRepl = function() {
12-
this.client = new baseDebugger.Client();
12+
this.client;
1313
this.replServer;
1414
this.cmdRepl;
1515
};
@@ -19,20 +19,8 @@ var WdRepl = function() {
1919
* @private
2020
*/
2121
WdRepl.prototype.initClient_ = function() {
22-
var client = this.client;
23-
24-
client.once('ready', function() {
25-
26-
client.setBreakpoint({
27-
type: 'scriptRegExp',
28-
target: '.*executors\.js', //jshint ignore:line
29-
line: 37
30-
}, function() {});
31-
});
32-
33-
var host = 'localhost';
34-
var port = process.argv[2] || 5858;
35-
client.connect(port, host); // TODO - might want to add retries here.
22+
this.client =
23+
debuggerCommons.attachDebugger(process.argv[2], process.argv[3]);
3624
};
3725

3826
/**
@@ -44,7 +32,7 @@ WdRepl.prototype.initClient_ = function() {
4432
* @param {function} callback
4533
*/
4634
WdRepl.prototype.stepEval_ = function(cmd, context, filename, callback) {
47-
cmd = cmd.slice(1, cmd.length - 2);
35+
cmd = debuggerCommons.trimReplCmd(cmd);
4836
this.cmdRepl.stepEval(cmd, callback);
4937
};
5038

lib/debugger/clients/wddebugger.js

+21-25
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
var repl = require('repl');
2-
var baseDebugger = require('_debugger');
2+
var debuggerCommons = require('../debuggerCommons');
33
var CommandRepl = require('../modes/commandRepl');
44
var DebuggerRepl = require('../modes/debuggerRepl');
55

@@ -11,7 +11,7 @@ var DebuggerRepl = require('../modes/debuggerRepl');
1111
* @constructor
1212
*/
1313
var WdDebugger = function() {
14-
this.client = new baseDebugger.Client();
14+
this.client;
1515
this.replServer;
1616

1717
// repl is broken into 'command repl' and 'debugger repl'.
@@ -26,28 +26,17 @@ var WdDebugger = function() {
2626
* @private
2727
*/
2828
WdDebugger.prototype.initClient_ = function() {
29-
var client = this.client;
30-
31-
client.once('ready', function() {
29+
this.client =
30+
debuggerCommons.attachDebugger(process.argv[2], process.argv[3]);
31+
this.client.once('ready', function() {
3232
console.log(' ready\n');
33-
34-
client.setBreakpoint({
35-
type: 'scriptRegExp',
36-
target: '.*executors\.js', //jshint ignore:line
37-
line: 37
38-
}, function() {
39-
console.log('press c to continue to the next webdriver command');
40-
console.log('press d to continue to the next debugger statement');
41-
console.log('type "repl" to enter interactive mode');
42-
console.log('type "exit" to break out of interactive mode');
43-
console.log('press ^C to exit');
44-
console.log();
45-
});
33+
console.log('press c to continue to the next webdriver command');
34+
console.log('press d to continue to the next debugger statement');
35+
console.log('type "repl" to enter interactive mode');
36+
console.log('type "exit" to break out of interactive mode');
37+
console.log('press ^C to exit');
38+
console.log();
4639
});
47-
48-
var host = 'localhost';
49-
var port = process.argv[2] || 5858;
50-
client.connect(port, host); // TODO - might want to add retries here.
5140
};
5241

5342
/**
@@ -60,19 +49,26 @@ WdDebugger.prototype.initClient_ = function() {
6049
*/
6150
WdDebugger.prototype.stepEval_ = function(cmd, context, filename, callback) {
6251
// The loop won't come back until 'callback' is called.
63-
// Strip out the () which the REPL adds and the new line.
6452
// Note - node's debugger gets around this by adding custom objects
6553
// named 'c', 's', etc to the REPL context. They have getters which
6654
// perform the desired function, and the callback is stored for later use.
6755
// Think about whether this is a better pattern.
68-
cmd = cmd.slice(1, cmd.length - 2);
56+
57+
cmd = debuggerCommons.trimReplCmd(cmd);
6958

7059
if (this.currentRepl === this.dbgRepl && cmd === 'repl' ||
7160
this.currentRepl === this.cmdRepl && cmd === 'exit') {
7261
// switch repl mode
7362
this.currentRepl =
7463
this.currentRepl === this.dbgRepl ? this.cmdRepl : this.dbgRepl;
75-
this.replServer.prompt = this.currentRepl.prompt;
64+
// For node backward compatibility. In older versions of node `setPrompt`
65+
// does not exist, and we set the prompt by overwriting `replServer.prompt`
66+
// directly.
67+
if (this.replServer.setPrompt) {
68+
this.replServer.setPrompt(this.currentRepl.prompt);
69+
} else {
70+
this.replServer.prompt = this.currentRepl.prompt;
71+
}
7672
this.replServer.complete = this.currentRepl.complete.bind(this.currentRepl);
7773
callback();
7874
} else {

lib/debugger/debuggerCommons.js

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
var baseDebugger = require('_debugger');
2+
3+
/**
4+
* Create a debugger client and attach to a running protractor process.
5+
* Set a break point at webdriver executor.
6+
* @param {number} pid Pid of the process to attach the debugger to.
7+
* @param {number=} opt_port Port to set up the debugger connection over.
8+
* @return {!baseDebugger.Client} The connected debugger client.
9+
*/
10+
exports.attachDebugger = function(pid, opt_port) {
11+
var client = new baseDebugger.Client();
12+
13+
client.once('ready', function() {
14+
client.setBreakpoint({
15+
type: 'scriptRegExp',
16+
target: '.*executors\.js', //jshint ignore:line
17+
line: 37
18+
}, function() {});
19+
});
20+
21+
process.debugPort = opt_port || 5858;
22+
// Call this private function instead of sending SIGUSR1 because Windows.
23+
process._debugProcess(pid);
24+
25+
var host = 'localhost';
26+
var connectWithRetry = function(attempts) {
27+
var socket = client.connect(process.debugPort, host);
28+
socket.on('connect', function() {
29+
client.reqContinue(function() {
30+
// Intentionally blank.
31+
});
32+
});
33+
socket.on('error', function(e) {
34+
if (attempts === 1) {
35+
throw e;
36+
} else {
37+
setTimeout(function() {
38+
connectWithRetry(attempts - 1);
39+
}, 200);
40+
}
41+
});
42+
};
43+
connectWithRetry(10);
44+
45+
return client;
46+
};
47+
48+
/**
49+
* Trim excess symbols from the repl command so that it is consistent with
50+
* the user input.
51+
* @param {string} cmd Cmd provided by the repl server.
52+
* @return {string} The trimmed cmd.
53+
*/
54+
exports.trimReplCmd = function(cmd) {
55+
// Given user input 'foobar', some versions of node provide '(foobar\n)',
56+
// while other versions of node provide 'foobar\n'.
57+
if (cmd.length >= 2 && cmd[0] === '(' && cmd[cmd.length - 1] === ')') {
58+
cmd = cmd.substring(1, cmd.length - 1);
59+
}
60+
return cmd.slice(0, cmd.length - 1);
61+
};

lib/protractor.js

+13-15
Original file line numberDiff line numberDiff line change
@@ -653,26 +653,26 @@ Protractor.prototype.initDebugger_ = function(debuggerClientPath, opt_debugPort)
653653
return asString;
654654
};
655655

656-
if (opt_debugPort) {
657-
process.debugPort = opt_debugPort;
658-
}
659-
660-
// Call this private function instead of sending SIGUSR1 because Windows.
661-
process._debugProcess(process.pid);
662-
656+
var vm_ = require('vm');
657+
var browserUnderDebug = this;
663658
var flow = webdriver.promise.controlFlow();
664-
var pausePromise = flow.execute(function() {
659+
660+
flow.execute(function() {
665661
log.puts('Starting WebDriver debugger in a child process. Pause is ' +
666662
'still beta, please report issues at github.com/angular/protractor\n');
667663
var nodedebug = require('child_process').
668-
fork(debuggerClientPath, [process.debugPort]);
664+
fork(debuggerClientPath,
665+
[process.pid, opt_debugPort || process.debugPort]);
669666
process.on('exit', function() {
670667
nodedebug.kill('SIGTERM');
671-
});
668+
});
672669
});
673-
674-
var vm_ = require('vm');
675-
var browserUnderDebug = this;
670+
671+
var pausePromise = flow.timeout(1000, 'waiting for debugger to attach')
672+
.then(function() {
673+
// Necessary for backward compatibility with node < 0.12.0
674+
browserUnderDebug.executeScript_('', 'empty debugger hook');
675+
});
676676

677677
// Helper used only by debuggers at './debugger/modes/*.js' to insert code
678678
// into the control flow.
@@ -773,8 +773,6 @@ Protractor.prototype.initDebugger_ = function(debuggerClientPath, opt_debugPort)
773773
return found;
774774
});
775775
};
776-
777-
flow.timeout(1000, 'waiting for debugger to attach');
778776
};
779777

780778
/**

0 commit comments

Comments
 (0)