@@ -824,17 +824,62 @@ Protractor.prototype.debugger = function() {
824
824
'add breakpoint to control flow' ) ;
825
825
} ;
826
826
827
+ /**
828
+ * Validates that the port is free to use. This will only validate the first
829
+ * time it is called. The reason is that on subsequent calls, the port will
830
+ * already be bound to the debugger, so it will not be available, but that is
831
+ * okay.
832
+ *
833
+ * @return {Promise<boolean> } A promise that becomes ready when the validation
834
+ * is done. The promise will resolve to a boolean which represents whether
835
+ * this is the first time that the debugger is called.
836
+ */
837
+ Protractor . prototype . validatePortAvailability_ = function ( port ) {
838
+ if ( this . debuggerValidated_ ) {
839
+ return webdriver . promise . fulfilled ( false ) ;
840
+ }
841
+ this . debuggerValidated_ = true ;
842
+
843
+ var doneDeferred = webdriver . promise . defer ( ) ;
844
+
845
+ // Resolve doneDeferred if port is available.
846
+ var net = require ( 'net' ) ;
847
+ var tester = net . connect ( { port : port } , function ( ) {
848
+ doneDeferred . reject ( 'Port ' + port +
849
+ ' is already in use. Please specify ' + 'another port to debug.' ) ;
850
+ } ) ;
851
+ tester . once ( 'error' , function ( err ) {
852
+ if ( err . code === 'ECONNREFUSED' ) {
853
+ tester . once ( 'close' , function ( ) {
854
+ doneDeferred . fulfill ( true ) ;
855
+ } ) . end ( ) ;
856
+ } else {
857
+ doneDeferred . reject (
858
+ 'Unexpected failure testing for port ' + port + ': ' +
859
+ JSON . stringify ( err ) ) ;
860
+ }
861
+ } ) ;
862
+
863
+ return doneDeferred . then ( null , function ( err ) {
864
+ console . error ( err ) ;
865
+ process . exit ( 1 ) ;
866
+ } ) ;
867
+ } ,
868
+
827
869
/**
828
870
* Helper function to:
829
871
* 1) Set up helper functions for debugger clients to call on (e.g.
830
872
* getControlFlowText, execute code, get autocompletion).
831
873
* 2) Enter process into debugger mode. (i.e. process._debugProcess).
832
874
* 3) Invoke the debugger client specified by debuggerClientPath.
833
875
*
834
- * @param {string= } debuggerClientPath Absolute path of debugger client to use
876
+ * @param {string } debuggerClientPath Absolute path of debugger client to use
877
+ * @param {Function } onStartFn Function to call when the debugger starts. The
878
+ * function takes a single parameter, which represents whether this is the
879
+ * first time that the debugger is called.
835
880
* @param {number= } opt_debugPort Optional port to use for the debugging process
836
881
*/
837
- Protractor . prototype . initDebugger_ = function ( debuggerClientPath , opt_debugPort ) {
882
+ Protractor . prototype . initDebugger_ = function ( debuggerClientPath , onStartFn , opt_debugPort ) {
838
883
// Patch in a function to help us visualize what's going on in the control
839
884
// flow.
840
885
webdriver . promise . ControlFlow . prototype . getControlFlowText = function ( ) {
@@ -847,26 +892,6 @@ Protractor.prototype.initDebugger_ = function(debuggerClientPath, opt_debugPort)
847
892
// hackier, and involves messing with the control flow's internals / private
848
893
// variables.
849
894
return helper . filterStackTrace ( controlFlowText ) ;
850
-
851
- } ;
852
-
853
- // Invoke fn if port is available.
854
- var onPortAvailable = function ( port , fn ) {
855
- var net = require ( 'net' ) ;
856
- var tester = net . connect ( { port : port } , function ( ) {
857
- console . error ( 'Port ' + port + ' is already in use. Please specify ' +
858
- 'another port to debug.' ) ;
859
- process . exit ( 1 ) ;
860
- } ) ;
861
- tester . once ( 'error' , function ( err ) {
862
- if ( err . code === 'ECONNREFUSED' ) {
863
- tester . once ( 'close' , fn ) . end ( ) ;
864
- } else {
865
- console . error ( 'Unexpected failure testing for port ' + port + ': ' ,
866
- err ) ;
867
- process . exit ( 1 ) ;
868
- }
869
- } ) ;
870
895
} ;
871
896
872
897
var vm_ = require ( 'vm' ) ;
@@ -892,11 +917,11 @@ Protractor.prototype.initDebugger_ = function(debuggerClientPath, opt_debugPort)
892
917
893
918
var browserUnderDebug = this ;
894
919
var debuggerReadyPromise = webdriver . promise . defer ( ) ;
895
- flow . execute ( function ( ) {
896
- log . puts ( 'Starting WebDriver debugger in a child process. Pause is ' +
897
- 'still beta, please report issues at github.com/angular/protractor\n' ) ;
920
+ flow . execute ( function ( ) {
898
921
process . debugPort = opt_debugPort || process . debugPort ;
899
- onPortAvailable ( process . debugPort , function ( ) {
922
+ browserUnderDebug . validatePortAvailability_ ( process . debugPort ) . then ( function ( firstTime ) {
923
+ onStartFn ( firstTime ) ;
924
+
900
925
var args = [ process . pid , process . debugPort ] ;
901
926
if ( browserUnderDebug . debuggerServerPort_ ) {
902
927
args . push ( browserUnderDebug . debuggerServerPort_ ) ;
@@ -1038,7 +1063,19 @@ Protractor.prototype.initDebugger_ = function(debuggerClientPath, opt_debugPort)
1038
1063
*/
1039
1064
Protractor . prototype . enterRepl = function ( opt_debugPort ) {
1040
1065
var debuggerClientPath = __dirname + '/debugger/clients/explorer.js' ;
1041
- this . initDebugger_ ( debuggerClientPath , opt_debugPort ) ;
1066
+ var onStartFn = function ( ) {
1067
+ log . puts ( ) ;
1068
+ log . puts ( '------- Element Explorer -------' ) ;
1069
+ log . puts ( 'Starting WebDriver debugger in a child process. Element ' +
1070
+ 'Explorer is still beta, please report issues at ' +
1071
+ 'github.com/angular/protractor' ) ;
1072
+ log . puts ( ) ;
1073
+ log . puts ( 'Type <tab> to see a list of locator strategies.' ) ;
1074
+ log . puts ( 'Use the `list` helper function to find elements by strategy:' ) ;
1075
+ log . puts ( ' e.g., list(by.binding(\'\')) gets all bindings.' ) ;
1076
+ log . puts ( ) ;
1077
+ } ;
1078
+ this . initDebugger_ ( debuggerClientPath , onStartFn , opt_debugPort ) ;
1042
1079
} ;
1043
1080
1044
1081
/**
@@ -1059,7 +1096,23 @@ Protractor.prototype.enterRepl = function(opt_debugPort) {
1059
1096
*/
1060
1097
Protractor . prototype . pause = function ( opt_debugPort ) {
1061
1098
var debuggerClientPath = __dirname + '/debugger/clients/wddebugger.js' ;
1062
- this . initDebugger_ ( debuggerClientPath , opt_debugPort ) ;
1099
+ var onStartFn = function ( firstTime ) {
1100
+ log . puts ( ) ;
1101
+ log . puts ( 'Encountered browser.pause(). Attaching debugger...' ) ;
1102
+ if ( firstTime ) {
1103
+ log . puts ( ) ;
1104
+ log . puts ( '------- WebDriver Debugger -------' ) ;
1105
+ log . puts ( 'Starting WebDriver debugger in a child process. Pause is ' +
1106
+ 'still beta, please report issues at github.com/angular/protractor' ) ;
1107
+ log . puts ( ) ;
1108
+ log . puts ( 'press c to continue to the next webdriver command' ) ;
1109
+ log . puts ( 'press ^D to detach debugger and resume code execution' ) ;
1110
+ log . puts ( 'type "repl" to enter interactive mode' ) ;
1111
+ log . puts ( 'type "exit" to break out of interactive mode' ) ;
1112
+ log . puts ( ) ;
1113
+ }
1114
+ } ;
1115
+ this . initDebugger_ ( debuggerClientPath , onStartFn , opt_debugPort ) ;
1063
1116
} ;
1064
1117
1065
1118
/**
0 commit comments