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

Commit fb099de

Browse files
committed
feat(elementExplorer): Combine browser.pause with elementExplorer
* reuse logic for browser.pause for elementExplorer * introduce browser.enterRepl * allow customization of driver for elementExplorer * fix bug where repl cannot return an ElementFinder (related #1600) Closes #1314, #1315
1 parent f9ce40d commit fb099de

File tree

10 files changed

+240
-146
lines changed

10 files changed

+240
-146
lines changed

bin/elementexplorer.js

+12-121
Original file line numberDiff line numberDiff line change
@@ -32,124 +32,15 @@
3232
* Typing tab at a blank prompt will fill in a suggestion for finding
3333
* elements.
3434
*/
35-
36-
var webdriver = require('selenium-webdriver');
37-
var protractor = require('../lib/protractor.js');
38-
var repl = require('repl');
39-
var util = require('util');
40-
var vm = require('vm');
41-
42-
var driver, browser;
43-
44-
var INITIAL_SUGGESTIONS = [
45-
'element(by.id(\'\'))',
46-
'element(by.css(\'\'))',
47-
'element(by.name(\'\'))',
48-
'element(by.binding(\'\'))',
49-
'element(by.xpath(\'\'))',
50-
'element(by.tagName(\'\'))',
51-
'element(by.className(\'\'))'
52-
];
53-
54-
var list = function(locator) {
55-
return browser.findElements(locator).then(function(arr) {
56-
var found = [];
57-
for (var i = 0; i < arr.length; ++i) {
58-
arr[i].getText().then(function(text) {
59-
found.push(text);
60-
});
61-
}
62-
return found;
63-
});
64-
};
65-
66-
var flowEval = function(code, context, file, callback) {
67-
68-
var vmErr,
69-
result,
70-
flow = webdriver.promise.controlFlow();
71-
72-
flow.execute(function() {
73-
try {
74-
result = vm.runInThisContext(code, file);
75-
} catch (e) {
76-
vmErr = e;
77-
callback(vmErr, null);
78-
}
79-
if (vmErr && process.domain) {
80-
process.domain.emit('error', vmErr);
81-
process.domain.exit();
82-
}
83-
84-
if (webdriver.promise.isPromise(result)) {
85-
return result.then(function(val) {return val});
86-
} else {
87-
return result;
88-
}
89-
}).then(function(res) {
90-
if (!vmErr) {
91-
callback(null, res);
92-
}
93-
}, function(err) {
94-
callback('There was a webdriver error: ' + err.name + ' ' + err.message,
95-
null);
96-
});
97-
};
98-
99-
var startRepl = function() {
100-
var flowRepl = repl.start({
101-
'useGlobal': true,
102-
'eval': flowEval
103-
});
104-
105-
var originalComplete = flowRepl.complete;
106-
107-
flowRepl.complete = function(line, completeCallback) {
108-
if (line == '') {
109-
completeCallback(null, [INITIAL_SUGGESTIONS, '']);
110-
} else {
111-
originalComplete.apply(this, arguments);
112-
}
113-
};
114-
115-
flowRepl.on('exit', function() {
116-
driver.quit();
117-
util.puts('Shutting down. Goodbye.');
118-
});
119-
};
120-
121-
var startUp = function() {
122-
driver = new webdriver.Builder().
123-
usingServer('http://localhost:4444/wd/hub').
124-
withCapabilities({'browserName': 'chrome'}).build();
125-
126-
driver.getSession().then(function(session) {
127-
driver.manage().timeouts().setScriptTimeout(11000);
128-
129-
browser = protractor.wrapDriver(driver);
130-
131-
// Set up globals to be available from the command line.
132-
global.driver = driver;
133-
global.protractor = protractor;
134-
global.browser = browser;
135-
global.$ = browser.$;
136-
global.$$ = browser.$$;
137-
global.element = browser.element;
138-
global.by = global.By = protractor.By;
139-
global.list = list;
140-
141-
142-
util.puts('Type <tab> to see a list of locator strategies.');
143-
util.puts('Use the `list` helper function to find elements by strategy:');
144-
util.puts(' e.g., list(by.binding(\'\')) gets all bindings.');
145-
util.puts('');
146-
147-
var url = process.argv[2] || 'about:blank';
148-
util.puts('Getting page at: ' + url);
149-
driver.get(url);
150-
151-
startRepl();
152-
});
153-
};
154-
155-
startUp();
35+
console.log('Please use "protractor [configFile] [options] --elementExplorer"' +
36+
' for full functionality\n');
37+
38+
if (process.argv.length > 3) {
39+
console.log('usage: elementexplorer.js [urL]');
40+
process.exit(1);
41+
} else if (process.argv.length === 3) {
42+
process.argv[2] = ('--baseUrl=' + process.argv[2]);
43+
}
44+
45+
process.argv.push('--elementExplorer');
46+
require('../lib/cli.js');

lib/cli.js

+10-1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ var optimist = require('optimist').
5151
describe('framework', 'Test framework to use: jasmine, cucumber or mocha').
5252
describe('resultJsonOutputFile', 'Path to save JSON test result').
5353
describe('troubleshoot', 'Turn on troubleshooting output').
54+
describe('elementExplorer', 'Interactively test Protractor commands').
5455
alias('browser', 'capabilities.browserName').
5556
alias('name', 'capabilities.name').
5657
alias('platform', 'capabilities.platform').
@@ -70,6 +71,11 @@ var optimist = require('optimist').
7071

7172
var argv = optimist.parse(args);
7273

74+
if (argv.help) {
75+
optimist.showHelp();
76+
process.exit(0);
77+
}
78+
7379
if (argv.version) {
7480
console.log('Version ' + require(path.join(__dirname, '../package.json')).version);
7581
process.exit(0);
@@ -123,7 +129,10 @@ if (!configFile) {
123129
configFile = './protractor.conf.js';
124130
}
125131
}
126-
if (!configFile && args.length < 3) {
132+
133+
if (!configFile && !argv.elementExplorer && args.length < 3) {
134+
console.log('**you must either specify a configuration file ' +
135+
'or at least 3 options. See below for the options:\n');
127136
optimist.showHelp();
128137
process.exit(1);
129138
}

lib/debugger/clients/explorer.js

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
var repl = require('repl');
2+
var baseDebugger = require('_debugger');
3+
var CommandRepl = require('../modes/commandRepl');
4+
5+
/**
6+
* BETA BETA BETA
7+
* Custom explorer to test protractor commands.
8+
*
9+
* @constructor
10+
*/
11+
var WdRepl = function() {
12+
this.client = new baseDebugger.Client();
13+
this.replServer;
14+
this.cmdRepl;
15+
};
16+
17+
/**
18+
* Initiate debugger client.
19+
* @private
20+
*/
21+
WdRepl.prototype.initClient_ = function() {
22+
var client = this.client;
23+
24+
client.once('ready', function() {
25+
26+
client.setBreakpoint({
27+
type: 'scriptRegExp',
28+
target: 'selenium-webdriver/executors.js',
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.
36+
};
37+
38+
/**
39+
* Eval function for processing a single step in repl.
40+
* @private
41+
* @param {string} cmd
42+
* @param {object} context
43+
* @param {string} filename
44+
* @param {function} callback
45+
*/
46+
WdRepl.prototype.stepEval_ = function(cmd, context, filename, callback) {
47+
cmd = cmd.slice(1, cmd.length - 2);
48+
this.cmdRepl.stepEval(cmd, callback);
49+
};
50+
51+
/**
52+
* Instantiate all repl objects, and debuggerRepl as current and start repl.
53+
* @private
54+
*/
55+
WdRepl.prototype.initRepl_ = function() {
56+
var self = this;
57+
this.cmdRepl = new CommandRepl(this.client);
58+
59+
self.replServer = repl.start({
60+
prompt: self.cmdRepl.prompt,
61+
input: process.stdin,
62+
output: process.stdout,
63+
eval: self.stepEval_.bind(self),
64+
useGlobal: false,
65+
ignoreUndefined: true
66+
});
67+
68+
self.replServer.complete = self.cmdRepl.complete.bind(self.cmdRepl);
69+
70+
self.replServer.on('exit', function() {
71+
console.log('Exiting...');
72+
self.client.req({command: 'disconnect'}, function() {
73+
// Intentionally blank.
74+
});
75+
});
76+
};
77+
78+
/**
79+
* Initiate the debugger.
80+
* @public
81+
*/
82+
WdRepl.prototype.init = function() {
83+
console.log('Type <tab> to see a list of locator strategies.');
84+
console.log('Use the `list` helper function to find elements by strategy:');
85+
console.log(' e.g., list(by.binding(\'\')) gets all bindings.');
86+
87+
this.initClient_();
88+
this.initRepl_();
89+
};
90+
91+
var wdRepl = new WdRepl();
92+
wdRepl.init();

lib/debugger/wddebugger.js lib/debugger/clients/wddebugger.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
var repl = require('repl');
22
var baseDebugger = require('_debugger');
3-
var CommandRepl = require('./commandRepl');
4-
var DebuggerRepl = require('./debuggerRepl');
3+
var CommandRepl = require('../modes/commandRepl');
4+
var DebuggerRepl = require('../modes/debuggerRepl');
55

66
/**
77
* BETA BETA BETA
File renamed without changes.
File renamed without changes.

lib/frameworks/explorer.js

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
var q = require('q');
2+
3+
/**
4+
* A framework which does not actually run any tests. It allows users to drop
5+
* into a repl loop to experiment with protractor commands.
6+
*
7+
* @param {Runner} runner The current Protractor Runner.
8+
* @return {q.Promise} Promise resolved with the test results
9+
*/
10+
exports.run = function(runner) {
11+
/* globals browser */
12+
return q.promise(function (resolve) {
13+
if (runner.getConfig().baseUrl) {
14+
browser.get(runner.getConfig().baseUrl);
15+
}
16+
browser.enterRepl();
17+
browser.executeScript_('', 'empty debugger hook').then(function() {
18+
resolve({
19+
failedCount: 0
20+
});
21+
});
22+
});
23+
};

lib/launcher.js

+23-2
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,8 @@ var init = function(configFile, additionalConfig) {
118118
// Run beforeLaunch
119119
helper.runFilenameOrFn_(config.configDir, config.beforeLaunch).then(function() {
120120

121-
// Set `multicapabilities` using `capabilities`, `multicapabilites`,
122-
// `getMultiCapabilities()`, or default
123121
return q.promise(function(resolve) {
122+
// 1) If getMultiCapabilities is set, resolve that as `multiCapabilities`.
124123
if (config.getMultiCapabilities &&
125124
typeof config.getMultiCapabilities === 'function') {
126125
if (config.multiCapabilities.length || config.capabilities) {
@@ -136,6 +135,8 @@ var init = function(configFile, additionalConfig) {
136135
resolve();
137136
}
138137
}).then(function() {
138+
// 2) Set `multicapabilities` using `capabilities`, `multicapabilites`,
139+
// or default
139140
if (config.capabilities) {
140141
if (config.multiCapabilities.length) {
141142
log.warn('You have specified both capabilites and ' +
@@ -153,6 +154,26 @@ var init = function(configFile, additionalConfig) {
153154
}
154155
});
155156
}).then(function() {
157+
// 3) If we're in `elementExplorer` mode, run only that.
158+
if (config.elementExplorer || config.framework === 'explorer') {
159+
if (config.multiCapabilities.length != 1) {
160+
throw new Error('Must specify only 1 browser while using elementExplorer');
161+
} else {
162+
config.capabilities = config.multiCapabilities[0];
163+
}
164+
config.framework = 'explorer';
165+
166+
var Runner = require('./runner');
167+
var runner = new Runner(config);
168+
return runner.run().then(function(exitCode) {
169+
process.exit(exitCode);
170+
}, function(err) {
171+
log_(err);
172+
process.exit(1);
173+
});
174+
}
175+
}).then(function() {
176+
// 4) Run tests.
156177
var scheduler = new TaskScheduler(config);
157178

158179
process.on('exit', function(code) {

0 commit comments

Comments
 (0)