Skip to content

Commit 3475dd7

Browse files
committed
Added a bunch of improvements to webdriver playback and scheduler including:
Added support for test results server for scheduled tests Added external plugin support for scheduler Added support for remote playback for tests using webdriver Added option for selecting how an existing window is used for webdriver playback Added close webdriver session toolbar button Added toolbar button for selecting a common browser for webdriver playback Improved webdriver playback Fixed failing gist creation Fixed counter in health service Added more health event logging Changed to secure urls where possible
1 parent 5e66e77 commit 3475dd7

27 files changed

+271
-27
lines changed

ide/main/src/content/debugger.js

+7
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ function Debugger(editor) {
2727
}
2828

2929
this.log.debug("init");
30+
this.editor.health.addEvent('debugger', 'initializing');
3031

3132
this.setState(Debugger.STOPPED);
3233

@@ -129,6 +130,7 @@ function Debugger(editor) {
129130
}
130131
return false;
131132
};
133+
this.editor.health.addEvent('debugger', 'initialized');
132134
}
133135
}
134136

@@ -189,6 +191,11 @@ Debugger.prototype.doContinue = function (step) {
189191
this.runner.continueCurrentTest();
190192
};
191193

194+
Debugger.prototype.closeWebDriverSession = function () {
195+
this.init();
196+
this.runner.closeSession();
197+
};
198+
192199
Debugger.prototype.showElement = function (locator) {
193200
this.init();
194201
this.runner.showElement(locator);

ide/main/src/content/editor.js

+38-2
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ function Editor(window) {
5151
self.updateExperimentalFeatures(self.app.getBooleanOption('enableExperimentalFeatures'));
5252
self.updateVisualEye(self.app.getBooleanOption('visualEye'));
5353
self.health.showAlerts(self.app.getBooleanOption('showHealthAlerts'));
54+
self.updateWebdriverBrowser(self.app.options.webDriverBrowserString);
5455
},
5556

5657
testSuiteChanged: function (testSuite) {
@@ -202,6 +203,12 @@ function Editor(window) {
202203
}
203204
}
204205

206+
// disable webdriver related toolbar buttons if webdriver playback is disabled
207+
if ( !this.app.getBooleanOption('executeUsingWebDriver') ) {
208+
document.getElementById("browser-button").disabled = true;
209+
document.getElementById("close-webdriver-button").disabled = true;
210+
}
211+
205212
this.updateViewTabs();
206213
this.infoPanel = new Editor.InfoPanel(this);
207214

@@ -732,10 +739,10 @@ Editor.prototype.submitDiagInfo = function(){
732739
};
733740
window.openDialog("chrome://selenium-ide/content/health/diag-info.xul", "diagInfo", "chrome,modal,resizable", data);
734741
if (data.data.length > 0) {
735-
GitHub.createGist("Selenium IDE diagnostic information", data).done(function(url){
742+
GitHub.createGistWithFiles("Selenium IDE diagnostic information", data).then(function(url){
736743
alert("Gist created with diagnostic information.\nPlease update the issue on https://github.com/SeleniumHQ/selenium/issues with this url.\nURL: " + url);
737744
}, function(response, success, status){
738-
alert("Gist creation failed with status " + status + "\nResponse:-\n" + (response || ''));
745+
alert("Gist creation failed with status " + status + " and response:-\n" + (response || ''));
739746
});
740747
}
741748
};
@@ -1030,6 +1037,35 @@ Editor.prototype.populateFormatsPopup = function (e, action, format) {
10301037
}
10311038
};
10321039

1040+
Editor.prototype.setWebdriverBrowser = function (browser) {
1041+
this.getOptions().webDriverBrowserString = browser;
1042+
this.updateWebdriverBrowser(browser);
1043+
};
1044+
1045+
Editor.prototype.updateWebdriverBrowser = function (browser) {
1046+
var class_name = "";
1047+
var tooltip = "";
1048+
if (browser == "firefox") {
1049+
class_name = "fx";
1050+
tooltip = "Webdriver playback in Firefox";
1051+
} else if (browser == "chrome") {
1052+
class_name = "gc";
1053+
tooltip = "Webdriver playback in Google Chrome";
1054+
} else if (browser == "internet explorer") {
1055+
class_name = "ie";
1056+
tooltip = "Webdriver playback in Internet Explorer";
1057+
} else if (browser == "safari") {
1058+
class_name = "sa";
1059+
tooltip = "Webdriver playback in Safari";
1060+
}
1061+
if ( !this.app.getBooleanOption('executeUsingWebDriver') ) {
1062+
tooltip = "Webdriver playback is off. Turn it on in the options.";
1063+
}
1064+
var btn = document.getElementById("browser-button");
1065+
btn.setAttribute('class', class_name);
1066+
btn.setAttribute('tooltiptext', tooltip);
1067+
};
1068+
10331069
Editor.prototype.updateViewTabs = function () {
10341070
var editorTab = $('editorTab');
10351071
var tabs = $('viewTabs');

ide/main/src/content/file-utils.js

+5
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ var FileUtils = {
3030
getFile: function(path) {
3131
var file = Components.classes['@mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile);
3232
file.initWithPath(path);
33+
if (arguments.length > 1) {
34+
for (var i = 1; i < arguments.length; i++) {
35+
file.append(arguments[i]);
36+
}
37+
}
3338
return file;
3439
},
3540

ide/main/src/content/health/health-service.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,8 @@ HealthService.prototype.attach = function(win, component) {
109109
oldOnError: oldOnError
110110
};
111111
var self = this;
112-
win.onerror = function SIDEErrorHandler(msg, url, line, column, error) {
112+
//TODO maybe use an add event listener to not overwrite any existing handlers?
113+
win.onerror = function(msg, url, line, column, error) {
113114
self.addError(component, "UncaughtException", msg, url, line, column, (error && error.stack ? error.stack : null));
114115
if (self.alerts) {
115116
try {
@@ -188,6 +189,8 @@ HealthService.prototype.addException = function(component, event, exception) {
188189
HealthService.prototype.increaseCounter = function(component, counter) {
189190
if (!this.stats[component]) {
190191
this.stats[component] = {};
192+
}
193+
if (!this.stats[component][counter]) {
191194
this.stats[component][counter] = 0;
192195
}
193196
this.stats[component][counter]++;
@@ -231,7 +234,7 @@ HealthService.prototype.getData = function() {
231234
* Return the collected data
232235
*/
233236
HealthService.prototype.getJSON = function(pretty) {
234-
return JSON.stringify(this.getData(), null, 2);
237+
return JSON.stringify(this.getData(), null, pretty ? 2 : null);
235238
};
236239

237240
/**

ide/main/src/content/optionsDialog.xul

+11
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,11 @@ limitations under the License.
9292
<checkbox id="enableExperimentalFeatures" label="&options.enableExperimentalFeatures.label;"/>
9393
<checkbox id="disableFormatChangeMsg" label="&options.disableFormatChangeMsg.label;"/>
9494
<checkbox id="recordOnOpen" label="&options.recordOnOpen.description;"/>
95+
<hbox>
96+
<description>Scheduled tests results server</description>
97+
<textbox id="jobResultsServer" multiline="false" flex="1"/>
98+
</hbox>
99+
<description class="tip">URL of server to send test results for scheduled tests</description>
95100
</tabpanel>
96101
<tabpanel id="formats" orient="vertical">
97102
<hbox flex="1">
@@ -154,9 +159,15 @@ limitations under the License.
154159
<description class="tip">Changes to this option will be applied after an Selenium IDE restart</description>
155160
<description class="tip">WebDriver playback is still an experimental feature and may not be very stable. Please use it for testing Selenium IDE to provide us feedback.</description>
156161
<hbox>
162+
<description>WebDriver browser string</description>
157163
<textbox id="webDriverBrowserString" multiline="false" flex="1"/>
158164
</hbox>
159165
<description class="tip">Browser choices: android, chrome, firefox, htmlunit, internet explorer, iPhone, iPad</description>
166+
<hbox>
167+
<description>Selenium server</description>
168+
<textbox id="webDriverServer" multiline="false" flex="1"/>
169+
</hbox>
170+
<description class="tip">Protocol, host and port where your Selenium server is running, e.g. http://localhost:4444</description>
160171
<label class="text-link" href="http://blog.reallysimplethoughts.com/?p=561" value="How to use WebDriver playback?" />
161172
</tabpanel>
162173
</tabpanels>

ide/main/src/content/preferences.js

+2
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,8 @@ SeleniumIDE.Preferences.DEFAULT_OPTIONS = {
155155
timeout: "30000",
156156
executeUsingWebDriver: "false",
157157
webDriverBrowserString: "firefox",
158+
webDriverReuseWindow: "always",
159+
webDriverServer: "http://localhost:4444", // Only protocol, host and port portion
158160

159161
//Scheduler related options
160162
jobResultsServer: 'http://localhost:3000/api/result',

ide/main/src/content/scheduler/scheduler-selenium.js

+29-11
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
*/
1818

1919
function SeleniumScheduler(editor) {
20+
this.editor = editor;
2021
var jobRunner = new JobRunner(editor);
2122
this.scheduler = Scheduler.fromData(FileUtils.readJSONStoredFile('scheduler.json', []), function(job) {
2223
jobRunner.run(job);
@@ -27,8 +28,13 @@ function SeleniumScheduler(editor) {
2728
this.schedulerMemoryWatcher = new MemoryWatcher(editor, this, jobRunner);
2829
this.jobRunnerWatchDog = new JobRunnerWatchDog(editor, this, jobRunner);
2930
//TODO plugins, plugin dependency
31+
this.plugins = {};
3032
}
3133

34+
SeleniumScheduler.prototype.addPlugin = function(id, ctorFn) {
35+
this.plugins[id] = ctorFn(this.editor, this, this.jobRunner);
36+
};
37+
3238
function JobRunner(editor) {
3339
this.editor = editor;
3440
this.job = null;
@@ -60,9 +66,11 @@ JobRunner.prototype.run = function(job) {
6066
if (job.action && job.action.suite && job.action.suite.length > 0) {
6167
this.editor.app.loadTestCaseWithNewSuite(job.action.suite);
6268
}
69+
var resultsFolder = FileUtils.getStoredTimeStampedFile('job_results');
70+
resultsFolder.append(FileUtils.getSafeFilename(job.title));
6371
//The following code is out of the above if block as it is a feature. Allow scheduling the currently open test suite if no suite is specified in the job
6472
//TODO check if it really loaded!
65-
this.notify('jobStarting', job);
73+
this.notify('jobStarting', job, resultsFolder.path);
6674
this.editor.playTestSuite();
6775
};
6876

@@ -113,20 +121,30 @@ SaveHTMLResults.prototype.getFolder = function() {
113121

114122
function PostResults(editor, seleniumScheduler, jobRunner) {
115123
this.editor = editor;
116-
this.dispatcher = new Dispatcher(null, editor.app.options.jobResultsServer);
124+
this.server = "http://localhost:3000/api/result";
125+
this.dispatcher = new Dispatcher(null, this.server);
117126
var self = this;
118127
if (jobRunner) {
119128
jobRunner.addObserver({
120129
jobComplete: function (job, result) {
121-
var testSuite = self.editor.app.getTestSuite();
122-
var data = {
123-
title: job.title,
124-
schedule: job.schedule.getData(),
125-
scheduledTime: job.nextRun.getTime(),
126-
startTime: job.startTime.getTime(),
127-
suite: testSuite.result()
128-
};
129-
self.dispatcher.send(data);
130+
var server = self.editor.app.options.jobResultsServer || "";
131+
server = server.trim();
132+
if (server.length > 0) { // set server to an empty string to turn off sending results
133+
if (server != self.server) {
134+
self.server = server;
135+
self.dispatcher.setServer(server);
136+
}
137+
self.editor.health.addEvent('postResults', 'sending results to ' + self.server);
138+
var testSuite = self.editor.app.getTestSuite();
139+
var data = {
140+
title: job.title,
141+
schedule: job.schedule.getData(),
142+
scheduledTime: job.nextRun.getTime(),
143+
startTime: job.startTime.getTime(),
144+
suite: testSuite.result()
145+
};
146+
self.dispatcher.send(data);
147+
}
130148
}
131149
});
132150
}

ide/main/src/content/selenium-ide-common.xul

+12-1
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,8 @@ limitations under the License.
217217
<menuitem label="&speedSliderFaster.label;" command="cmd_selenium_speed_faster" accesskey="-"/>
218218
<menuitem label="&speedSliderSlower.label;" command="cmd_selenium_speed_slower" accesskey="+"/>
219219
<menuitem label="&speedSliderSlowest.label;" command="cmd_selenium_speed_slowest" accesskey="9"/>
220+
<menuseparator/>
221+
<menuitem label="Close webdriver session" oncommand="window.editor.selDebugger.closeWebDriverSession()"/>
220222
</menupopup>
221223
</menu>
222224
<menu id="optionsMenu" label="&optionsMenu.label;" accesskey="O">
@@ -251,7 +253,7 @@ limitations under the License.
251253
<menuitem label="&helpSubmitDiagInfo.label;" oncommand="window.editor.submitDiagInfo();"/>
252254
<menuseparator/>
253255
<menuitem label="&helpReleaseNotes.label;" oncommand="openTabOrWindow('https://github.com/SeleniumHQ/selenium/wiki/SeIDE-Release-Notes')"/>
254-
<menuitem label="&helpBlog.label;" oncommand="openTabOrWindow('http://seleniumhq.wordpress.com/')"/>
256+
<menuitem label="&helpBlog.label;" oncommand="openTabOrWindow('https://seleniumhq.wordpress.com/')"/>
255257
<menuitem label="&helpWebsite.label;" oncommand="openTabOrWindow('http://seleniumhq.org/')"/>
256258
</menupopup>
257259
</menu>
@@ -276,6 +278,15 @@ limitations under the License.
276278
</stack>
277279
</vbox>
278280
</stack>
281+
282+
<toolbarbutton id="browser-button" type="menu-button" label="WebDriver" class="toolbar2 toolbarbutton-1" tooltiptext="Webdriver playback is off. Turn on in the options.">
283+
<menupopup id="webdriverPopup">
284+
<menuitem label="Firefox" value="firefox" oncommand="window.editor.setWebdriverBrowser(event.target.getAttribute('value'));" />
285+
<menuitem label="Google Chrome" value="chrome" oncommand="window.editor.setWebdriverBrowser(event.target.getAttribute('value'));" />
286+
<menuitem label="Internet Explorer" value="internet explorer" oncommand="window.editor.setWebdriverBrowser(event.target.getAttribute('value'));" />
287+
<menuitem label="Safari" value="safari" oncommand="window.editor.setWebdriverBrowser(event.target.getAttribute('value'));" />
288+
</menupopup>
289+
</toolbarbutton>
279290
<toolbarbutton id="schedule-button" type="menu-button" label="Scheduler" class="toolbar2 toolbarbutton-1" tooltiptext="Click to turn scheduler on" command="cmd_selenium_schedule">
280291
<menupopup id="schedulerPopup">
281292
<menuitem label="Play test suites periodically" oncommand="window.editor.openSeleniumIDEScheduler(event);" />

ide/main/src/content/selenium-ide.xul

+3
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ limitations under the License.
8282
<toolbarseparator/>
8383
<toolbarbutton id="rollup-button" label="Rollup" class="icon" tooltiptext="&rollupButton.tooltip;" command="cmd_selenium_rollup"/>
8484
<toolbarbutton id="reload-button" label="Reload" class="icon" tooltiptext="&reloadExtButton.tooltip;" command="cmd_selenium_reload" hidden="true"/>
85+
<toolbarseparator/>
86+
<toolbarbutton id="browser-button"/>
87+
<toolbarbutton id="close-webdriver-button" label="Close Webdriver" class="toolbar2 toolbarbutton-1" tooltiptext="Close Webdriver session to the Selenium Server" oncommand="window.editor.selDebugger.closeWebDriverSession()"/>
8588
<toolbarspacer flex="1"/>
8689
<toolbarbutton id="schedule-button"/>
8790
<toolbarbutton id="record-button" label="Record" class="icon" tooltiptext="&recordButton.tooltip;" checked="true" command="cmd_selenium_record"/>

ide/main/src/content/selenium-runner.js

+10-1
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,9 @@ function start(baseURL, handler, useLastWindow) {
400400
//Samit: use the web driver backed selenium
401401
if (this.executeUsingWebDriver) {
402402
var webDriverBrowserString = this.editor.getOptions().webDriverBrowserString;
403-
selenium = new WebdriverBackedSelenium(baseURL, webDriverBrowserString);
403+
var reuseBrowser = this.editor.getOptions().webDriverReuseWindow;
404+
var server = this.editor.getOptions().webDriverServer;
405+
selenium = new WebdriverBackedSelenium(baseURL, useLastWindow, webDriverBrowserString, reuseBrowser, server);
404406
} else {
405407
selenium = createSelenium(baseURL, useLastWindow);
406408
selenium.browserbot.selectWindow(null);
@@ -419,6 +421,13 @@ function start(baseURL, handler, useLastWindow) {
419421
//setState(Debugger.PLAYING);
420422
}
421423

424+
function closeSession() {
425+
//Samit: If we are using the web driver backed selenium, close the session
426+
if (this.executeUsingWebDriver && WebdriverBackedSelenium && WebdriverBackedSelenium.closeWebdriverSession) {
427+
WebdriverBackedSelenium.closeWebdriverSession();
428+
}
429+
}
430+
422431
function executeCommand(baseURL, command) {
423432
//if (!stopAndDo("executeCommand", baseURL, command)) return;
424433
resetCurrentTest();

ide/main/src/content/utils/dispatcher.js

+6
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ function Dispatcher(queuePath, server) {
2222
this.queuePath = queuePath;
2323
}
2424

25+
26+
Dispatcher.prototype.setServer = function(server) {
27+
this.server = server;
28+
};
29+
30+
2531
Dispatcher.prototype.send = function(data) {
2632
return HTTP.post(this.server, data);
2733
// TODO convert and persist in queue

ide/main/src/content/utils/gist.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ GitHub.createGistWithFiles = function(description, files) {
5555
};
5656
return new Deferred(function(deferred) {
5757
HTTP.post('https://api.github.com/gists', data, {}, function(response, success, status) {
58-
if (status == 201 && response) {
58+
if (response && (status == "201")) {
5959
var result = JSON.parse(response);
6060
if (result.html_url) {
6161
deferred.resolve(result.html_url);

ide/main/src/content/utils/http.js

+15-1
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,15 @@ HTTP.request = function(method, url, data, headers, callback) {
5656
} else if (httpRequest.status === 500 ) {
5757
callback(httpRequest.responseText, false, httpRequest.status);
5858
} else {
59+
callback(httpRequest.responseText, false, httpRequest.status);
5960
//TODO eliminate alert and signal the failure
6061
// alert('There was a problem with the request.\nUrl: ' + url + '\nHttp Status: ' + httpRequest.status + "\nResponse: " + httpRequest.responseText);
6162
LOG.debug('Error: There was a problem with the request.\nUrl: ' + url + '\nHttp Status: ' + httpRequest.status + "\nResponse: " + httpRequest.responseText);
62-
callback(null, false, httpRequest.status);
6363
}
6464
}
6565
} catch(e) {
6666
//TODO eliminate alert and signal the failure, typically when callback is not given and Deferred is not loaded
67+
//LOG.error('Error: There was a problem with the request.\nUrl: ' + url + '\nHttp Status: ' + httpRequest.status + "\nResponse: " + httpRequest.responseText);
6768
alert('Caught Exception in HTTP.request: ' + e);
6869
throw e;
6970
}
@@ -114,3 +115,16 @@ HTTP.get = function (url, headers, callback) {
114115
return this.request('GET', url, null, headers, callback);
115116
};
116117

118+
/**
119+
* Shortcut method to create HTTP DELETE requests. See HTTP.request() for more details.
120+
*
121+
* @param url
122+
* @param {Object.<string, string>} [headers] hash with keys containing header names and values containing its value
123+
* @param {function(string, string, string)} [callback] a callback function that takes response, success, status. If callback is not given,
124+
* a deferred object is created. If deferred.js is not loaded, an exception occurs.
125+
* @returns {Deferred} if a deferred has been created
126+
*/
127+
HTTP._delete = function (url, headers, callback) {
128+
return this.request('DELETE', url, null, headers, callback);
129+
};
130+

0 commit comments

Comments
 (0)