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

Commit

Permalink
feat(elementExplorer): Combine browser.pause with elementExplorer
Browse files Browse the repository at this point in the history
  * 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
  • Loading branch information
hankduan committed Jan 13, 2015
1 parent f9ce40d commit fb099de
Show file tree
Hide file tree
Showing 10 changed files with 240 additions and 146 deletions.
133 changes: 12 additions & 121 deletions bin/elementexplorer.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,124 +32,15 @@
* Typing tab at a blank prompt will fill in a suggestion for finding
* elements.
*/

var webdriver = require('selenium-webdriver');
var protractor = require('../lib/protractor.js');
var repl = require('repl');
var util = require('util');
var vm = require('vm');

var driver, browser;

var INITIAL_SUGGESTIONS = [
'element(by.id(\'\'))',
'element(by.css(\'\'))',
'element(by.name(\'\'))',
'element(by.binding(\'\'))',
'element(by.xpath(\'\'))',
'element(by.tagName(\'\'))',
'element(by.className(\'\'))'
];

var list = function(locator) {
return browser.findElements(locator).then(function(arr) {
var found = [];
for (var i = 0; i < arr.length; ++i) {
arr[i].getText().then(function(text) {
found.push(text);
});
}
return found;
});
};

var flowEval = function(code, context, file, callback) {

var vmErr,
result,
flow = webdriver.promise.controlFlow();

flow.execute(function() {
try {
result = vm.runInThisContext(code, file);
} catch (e) {
vmErr = e;
callback(vmErr, null);
}
if (vmErr && process.domain) {
process.domain.emit('error', vmErr);
process.domain.exit();
}

if (webdriver.promise.isPromise(result)) {
return result.then(function(val) {return val});
} else {
return result;
}
}).then(function(res) {
if (!vmErr) {
callback(null, res);
}
}, function(err) {
callback('There was a webdriver error: ' + err.name + ' ' + err.message,
null);
});
};

var startRepl = function() {
var flowRepl = repl.start({
'useGlobal': true,
'eval': flowEval
});

var originalComplete = flowRepl.complete;

flowRepl.complete = function(line, completeCallback) {
if (line == '') {
completeCallback(null, [INITIAL_SUGGESTIONS, '']);
} else {
originalComplete.apply(this, arguments);
}
};

flowRepl.on('exit', function() {
driver.quit();
util.puts('Shutting down. Goodbye.');
});
};

var startUp = function() {
driver = new webdriver.Builder().
usingServer('http://localhost:4444/wd/hub').
withCapabilities({'browserName': 'chrome'}).build();

driver.getSession().then(function(session) {
driver.manage().timeouts().setScriptTimeout(11000);

browser = protractor.wrapDriver(driver);

// Set up globals to be available from the command line.
global.driver = driver;
global.protractor = protractor;
global.browser = browser;
global.$ = browser.$;
global.$$ = browser.$$;
global.element = browser.element;
global.by = global.By = protractor.By;
global.list = list;


util.puts('Type <tab> to see a list of locator strategies.');
util.puts('Use the `list` helper function to find elements by strategy:');
util.puts(' e.g., list(by.binding(\'\')) gets all bindings.');
util.puts('');

var url = process.argv[2] || 'about:blank';
util.puts('Getting page at: ' + url);
driver.get(url);

startRepl();
});
};

startUp();
console.log('Please use "protractor [configFile] [options] --elementExplorer"' +
' for full functionality\n');

if (process.argv.length > 3) {
console.log('usage: elementexplorer.js [urL]');
process.exit(1);
} else if (process.argv.length === 3) {
process.argv[2] = ('--baseUrl=' + process.argv[2]);
}

process.argv.push('--elementExplorer');
require('../lib/cli.js');
11 changes: 10 additions & 1 deletion lib/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ var optimist = require('optimist').
describe('framework', 'Test framework to use: jasmine, cucumber or mocha').
describe('resultJsonOutputFile', 'Path to save JSON test result').
describe('troubleshoot', 'Turn on troubleshooting output').
describe('elementExplorer', 'Interactively test Protractor commands').
alias('browser', 'capabilities.browserName').
alias('name', 'capabilities.name').
alias('platform', 'capabilities.platform').
Expand All @@ -70,6 +71,11 @@ var optimist = require('optimist').

var argv = optimist.parse(args);

if (argv.help) {
optimist.showHelp();
process.exit(0);
}

if (argv.version) {
console.log('Version ' + require(path.join(__dirname, '../package.json')).version);
process.exit(0);
Expand Down Expand Up @@ -123,7 +129,10 @@ if (!configFile) {
configFile = './protractor.conf.js';
}
}
if (!configFile && args.length < 3) {

if (!configFile && !argv.elementExplorer && args.length < 3) {
console.log('**you must either specify a configuration file ' +
'or at least 3 options. See below for the options:\n');
optimist.showHelp();
process.exit(1);
}
Expand Down
92 changes: 92 additions & 0 deletions lib/debugger/clients/explorer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
var repl = require('repl');
var baseDebugger = require('_debugger');
var CommandRepl = require('../modes/commandRepl');

/**
* BETA BETA BETA
* Custom explorer to test protractor commands.
*
* @constructor
*/
var WdRepl = function() {
this.client = new baseDebugger.Client();
this.replServer;
this.cmdRepl;
};

/**
* Initiate debugger client.
* @private
*/
WdRepl.prototype.initClient_ = function() {
var client = this.client;

client.once('ready', function() {

client.setBreakpoint({
type: 'scriptRegExp',
target: 'selenium-webdriver/executors.js',
line: 37
}, function() {});
});

var host = 'localhost';
var port = process.argv[2] || 5858;
client.connect(port, host); // TODO - might want to add retries here.
};

/**
* Eval function for processing a single step in repl.
* @private
* @param {string} cmd
* @param {object} context
* @param {string} filename
* @param {function} callback
*/
WdRepl.prototype.stepEval_ = function(cmd, context, filename, callback) {
cmd = cmd.slice(1, cmd.length - 2);
this.cmdRepl.stepEval(cmd, callback);
};

/**
* Instantiate all repl objects, and debuggerRepl as current and start repl.
* @private
*/
WdRepl.prototype.initRepl_ = function() {
var self = this;
this.cmdRepl = new CommandRepl(this.client);

self.replServer = repl.start({
prompt: self.cmdRepl.prompt,
input: process.stdin,
output: process.stdout,
eval: self.stepEval_.bind(self),
useGlobal: false,
ignoreUndefined: true
});

self.replServer.complete = self.cmdRepl.complete.bind(self.cmdRepl);

self.replServer.on('exit', function() {
console.log('Exiting...');
self.client.req({command: 'disconnect'}, function() {
// Intentionally blank.
});
});
};

/**
* Initiate the debugger.
* @public
*/
WdRepl.prototype.init = function() {
console.log('Type <tab> to see a list of locator strategies.');
console.log('Use the `list` helper function to find elements by strategy:');
console.log(' e.g., list(by.binding(\'\')) gets all bindings.');

this.initClient_();
this.initRepl_();
};

var wdRepl = new WdRepl();
wdRepl.init();
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
var repl = require('repl');
var baseDebugger = require('_debugger');
var CommandRepl = require('./commandRepl');
var DebuggerRepl = require('./debuggerRepl');
var CommandRepl = require('../modes/commandRepl');
var DebuggerRepl = require('../modes/debuggerRepl');

/**
* BETA BETA BETA
Expand Down
File renamed without changes.
File renamed without changes.
23 changes: 23 additions & 0 deletions lib/frameworks/explorer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
var q = require('q');

/**
* A framework which does not actually run any tests. It allows users to drop
* into a repl loop to experiment with protractor commands.
*
* @param {Runner} runner The current Protractor Runner.
* @return {q.Promise} Promise resolved with the test results
*/
exports.run = function(runner) {
/* globals browser */
return q.promise(function (resolve) {
if (runner.getConfig().baseUrl) {
browser.get(runner.getConfig().baseUrl);
}
browser.enterRepl();
browser.executeScript_('', 'empty debugger hook').then(function() {
resolve({
failedCount: 0
});
});
});
};
25 changes: 23 additions & 2 deletions lib/launcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,8 @@ var init = function(configFile, additionalConfig) {
// Run beforeLaunch
helper.runFilenameOrFn_(config.configDir, config.beforeLaunch).then(function() {

// Set `multicapabilities` using `capabilities`, `multicapabilites`,
// `getMultiCapabilities()`, or default
return q.promise(function(resolve) {
// 1) If getMultiCapabilities is set, resolve that as `multiCapabilities`.
if (config.getMultiCapabilities &&
typeof config.getMultiCapabilities === 'function') {
if (config.multiCapabilities.length || config.capabilities) {
Expand All @@ -136,6 +135,8 @@ var init = function(configFile, additionalConfig) {
resolve();
}
}).then(function() {
// 2) Set `multicapabilities` using `capabilities`, `multicapabilites`,
// or default
if (config.capabilities) {
if (config.multiCapabilities.length) {
log.warn('You have specified both capabilites and ' +
Expand All @@ -153,6 +154,26 @@ var init = function(configFile, additionalConfig) {
}
});
}).then(function() {
// 3) If we're in `elementExplorer` mode, run only that.
if (config.elementExplorer || config.framework === 'explorer') {
if (config.multiCapabilities.length != 1) {
throw new Error('Must specify only 1 browser while using elementExplorer');
} else {
config.capabilities = config.multiCapabilities[0];
}
config.framework = 'explorer';

var Runner = require('./runner');
var runner = new Runner(config);
return runner.run().then(function(exitCode) {
process.exit(exitCode);
}, function(err) {
log_(err);
process.exit(1);
});
}
}).then(function() {
// 4) Run tests.
var scheduler = new TaskScheduler(config);

process.on('exit', function(code) {
Expand Down
Loading

0 comments on commit fb099de

Please sign in to comment.