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

Commit a3e8b43

Browse files
cnishinajuliemr
authored andcommitted
deps(selenium-webdriver): upgrade to selenium 3 (#3781)
Note: with the upgrade, there might have breaking changes. Please see the selenium-webdriver changelog. - See [selenium-webdriver changelog](https://github.com/SeleniumHQ/selenium/blob/master/javascript/node/selenium-webdriver/CHANGES.md) - Removed method `WebDriver.prototype.isElementPresent` - Removed method `WebElement.prototype.getRawId` - Removed `getInnerHtml` and `getOutterHtml` - Dependency required for upgrade: use `[email protected]`. - Selenium-webdriver requires node version 6+, updating travis and circle yml to use node 6 and 7. - Use `instanceof` selenium-webdriver error instead of error code. Selenium-webdriver error codes have been deprecated. - Use executor with selenium-webdriver from `lib/http`. Deferred executor has been deprecated. - Fix quitting `driverProviders`. When calling `webdriver.quit`, the control flow is shutdown and will throw an error. - Driver provider for direct connect has been modified to use `ServiceBuilder` and to call the `Service` to `createSession` - Note: Since this upgrade is still using FF 47, direct connect for Firefox is required to pass "marionette: false" in the capabilities. If you do not pass marionette to false, it will look for gecko driver in the PATH. - Added a TODO to support FF after 48+ with direct connect and gecko driver. - Updated `browser.manage().addCookie('testcookie', 'Jane-1234');` to use `browser.manage().addCookie({name:'testcookie', value: 'Jane-1234'});` - Updated debug commons for breakpoint updated to selenium-webdriver `lib/http` line 432. - Debugger currently does not work. So `elementExplorer` for this current commit does not work. Additional work is required. - Since debugger does not work, interactive tests were disabled in `scripts/tests.js` - For mocha tests, `selenium-webdriver/testing` uses the global `it` and cannot be reassigned as Protractor's global `it`. Some code has been copied / modified to `lib/frameworks/mocha` to make this work. - Capabilities for Firefox 47 requires setting marionette to false. - Setup still requires selenium standalone server 2.53.1 for Firefox tests. Firefox version used is 47. - Using selenium standalone server 3, with Firefox 48+ tests fail with gecko driver still do not work. - Selenium standalone 3 + FF 49 + gecko driver 0.11.1 does not work - Selenium standalone 3 + FF 48 + gecko driver 0.11.1 appears to work for a single test but after it quits, selenium standalone no longer works with firefox. When firefox 48 exists, logs show the following: ``` 20:01:14.814 INFO - Executing: [delete session: e353fa1b-e266-4ec3-afb3-88f11a82473a]) [GFX1-]: Receive IPC close with reason=AbnormalShutdown [Child 30665] ###!!! ABORT: Aborting on channel error.: file /builds/slave/m-rel-m64-00000000000000000000/build/src/ipc/glue/MessageChannel.cpp, line 2052 [Child 30665] ###!!! ABORT: Aborting on channel error.: file /builds/slave/m-rel-m64-00000000000000000000/build/src/ipc/glue/MessageChannel.cpp, line 2052 ``` To be squashed - fix up attach session typo
1 parent eb31c9c commit a3e8b43

18 files changed

+211
-113
lines changed

.travis.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
language: node_js
22
sudo: false
33
node_js:
4-
- "4"
54
- "6"
5+
- "7"
66

77
env:
88
global:
@@ -24,9 +24,9 @@ matrix:
2424
- env: "JOB=bstack"
2525
exclude:
2626
- env: JOB=smoke
27-
node_js: "6"
27+
node_js: "7"
2828
- env: JOB=bstack
29-
node_js: "6"
29+
node_js: "7"
3030

3131
addons:
3232
apt:

circle.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
machine:
2+
node:
3+
version: 6.9.1
24
environment:
35
# Fix issue with selenium-server in containers.
46
# See http://github.com/SeleniumHQ/docker-selenium/issues/87
57
DBUS_SESSION_BUS_ADDRESS: /dev/null
6-
post:
7-
- npm install -g npm@3
88

99
dependencies:
1010
override:

lib/debugger.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ export class DebugHelper {
106106
});
107107

108108
let pausePromise = flow.execute(() => {
109-
return debuggerReadyPromise.then(() => {
109+
return debuggerReadyPromise.promise.then(() => {
110110
// Necessary for backward compatibility with node < 0.12.0
111111
return this.browserUnderDebug_.executeScriptWithDescription('', 'empty debugger hook');
112112
});
@@ -255,7 +255,7 @@ export class DebugHelper {
255255
}
256256
});
257257

258-
return doneDeferred.then(
258+
return doneDeferred.promise.then(
259259
() => {
260260
this.debuggerValidated_ = true;
261261
},

lib/debugger/debuggerCommons.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ exports.attachDebugger = function(pid, opt_port) {
1717
client.once('ready', function() {
1818
client.setBreakpoint({
1919
type: 'scriptRegExp',
20-
target: '.*command\.js', //jshint ignore:line
21-
line: 250
20+
target: 'lib/http\.js', //jshint ignore:line
21+
line: 432
2222
}, function() {
2323
process.send('ready');
2424
client.reqContinue(function() {

lib/driverProviders/attachSession.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@
55
*/
66
import * as q from 'q';
77
import {WebDriver} from 'selenium-webdriver';
8-
import * as executors from 'selenium-webdriver/executors';
98

109
import {Config} from '../config';
1110
import {Logger} from '../logger';
1211

1312
import {DriverProvider} from './driverProvider';
1413

14+
const http = require('selenium-webdriver/http');
15+
1516
let logger = new Logger('attachSession');
1617

1718
export class AttachSession extends DriverProvider {
@@ -38,8 +39,9 @@ export class AttachSession extends DriverProvider {
3839
* @return {WebDriver} webdriver instance
3940
*/
4041
getNewDriver(): WebDriver {
41-
let executor = executors.createExecutor(this.config_.seleniumAddress);
42-
let newDriver = WebDriver.attachToSession(executor, this.config_.seleniumSessionId);
42+
var httpClient = new http.HttpClient(this.config_.seleniumAddress);
43+
var executor = new http.Executor(httpClient);
44+
var newDriver = WebDriver.attachToSession(executor, this.config_.seleniumSessionId);
4345
this.drivers_.push(newDriver);
4446
return newDriver;
4547
}

lib/driverProviders/direct.ts

+7-3
Original file line numberDiff line numberDiff line change
@@ -75,14 +75,18 @@ export class Direct extends DriverProvider {
7575
'. Run \'webdriver-manager update\' to download binaries.');
7676
}
7777

78-
let service = new ChromeServiceBuilder(chromeDriverFile).build();
79-
driver = new ChromeDriver(new Capabilities(this.config_.capabilities), service);
78+
let chromeService = new ChromeServiceBuilder(chromeDriverFile).build();
79+
driver = ChromeDriver.createSession(new Capabilities(this.config_.capabilities), chromeService);
8080
break;
8181
case 'firefox':
8282
if (this.config_.firefoxPath) {
8383
this.config_.capabilities['firefox_binary'] = this.config_.firefoxPath;
8484
}
85-
driver = new FirefoxDriver(this.config_.capabilities);
85+
86+
// TODO(cnishina): Add in a service builder with marionette. Direct connect
87+
// currently supports FF legacy version 47.
88+
driver =
89+
FirefoxDriver.createSession(new Capabilities(this.config_.capabilities));
8690
break;
8791
default:
8892
throw new BrowserError(

lib/element.ts

+7-7
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ export interface WebdriverWebElement extends WebElement {}
1414

1515
let WEB_ELEMENT_FUNCTIONS = [
1616
'click', 'sendKeys', 'getTagName', 'getCssValue', 'getAttribute', 'getText', 'getSize',
17-
'getLocation', 'isEnabled', 'isSelected', 'submit', 'clear', 'isDisplayed', 'getOuterHtml',
18-
'getInnerHtml', 'getId', 'getRawId', 'serialize', 'takeScreenshot'
17+
'getLocation', 'isEnabled', 'isSelected', 'submit', 'clear', 'isDisplayed', 'getId', 'serialize',
18+
'takeScreenshot'
1919
] as (keyof WebdriverWebElement)[];
2020

2121
/**
@@ -419,8 +419,8 @@ export class ElementArrayFinder extends WebdriverWebElement {
419419
(arr: WebElement[]) => {
420420
return arr.length;
421421
},
422-
(err: IError) => {
423-
if (err.code && err.code == (new wderror.NoSuchSessionError() as any).code) {
422+
(err: Error) => {
423+
if (err instanceof wderror.NoSuchElementError) {
424424
return 0;
425425
} else {
426426
throw err;
@@ -1065,15 +1065,15 @@ export class ElementFinder extends WebdriverWebElement {
10651065
return true; // is present, whether it is enabled or not
10661066
},
10671067
(err: any) => {
1068-
if (err.code == (new wderror.StaleElementReferenceError() as any).code) {
1068+
if (err instanceof wderror.StaleElementReferenceError) {
10691069
return false;
10701070
} else {
10711071
throw err;
10721072
}
10731073
});
10741074
},
1075-
(err: any) => {
1076-
if (err.code == (new wderror.NoSuchElementError() as any).code) {
1075+
(err: Error) => {
1076+
if (err instanceof wderror.NoSuchElementError) {
10771077
return false;
10781078
} else {
10791079
throw err;

lib/expectedConditions.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ export class ProtractorExpectedConditions {
160160
return true;
161161
},
162162
(err: any) => {
163-
if (err.code == (new wderror.NoSuchAlertError() as any).code) {
163+
if (err instanceof wderror.NoSuchAlertError) {
164164
return false;
165165
} else {
166166
throw err;

lib/frameworks/mocha.js

+118-14
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
var q = require('q');
2+
var promise = require('selenium-webdriver').promise;
23

34
/**
45
* Execute the Runner's test cases through Mocha.
@@ -17,19 +18,14 @@ exports.run = function(runner, specs) {
1718
// wait until then to load mocha-webdriver adapters as well.
1819
mocha.suite.on('pre-require', function() {
1920
try {
20-
// We need to re-wrap all of the global functions, which selenium-webdriver/
21-
// testing only does when it is required. So first we must remove it from
22-
// the cache.
23-
delete require.cache[require.resolve('selenium-webdriver/testing')];
24-
var mochaAdapters = require('selenium-webdriver/testing');
25-
global.after = mochaAdapters.after;
26-
global.afterEach = mochaAdapters.afterEach;
27-
global.before = mochaAdapters.before;
28-
global.beforeEach = mochaAdapters.beforeEach;
29-
30-
global.it = mochaAdapters.it;
31-
global.it.only = global.iit = mochaAdapters.iit;
32-
global.it.skip = global.xit = mochaAdapters.xit;
21+
global.after = wrapped(global.after);
22+
global.afterEach = wrapped(global.afterEach);
23+
global.before = wrapped(global.before);
24+
global.beforeEach = wrapped(global.beforeEach);
25+
26+
global.it = wrapped(global.it);
27+
global.it.only = wrapped(global.iit);
28+
global.it.skip = wrapped(global.xit);
3329
} catch (err) {
3430
deferred.reject(err);
3531
}
@@ -38,7 +34,6 @@ exports.run = function(runner, specs) {
3834
mocha.loadFiles();
3935

4036
runner.runTestPreparer().then(function() {
41-
4237
specs.forEach(function(file) {
4338
mocha.addFile(file);
4439
});
@@ -99,3 +94,112 @@ exports.run = function(runner, specs) {
9994

10095
return deferred.promise;
10196
};
97+
98+
99+
100+
var flow = (function() {
101+
var initial = process.env['SELENIUM_PROMISE_MANAGER'];
102+
try {
103+
process.env['SELENIUM_PROMISE_MANAGER'] = '1';
104+
return promise.controlFlow();
105+
} finally {
106+
if (initial === undefined) {
107+
delete process.env['SELENIUM_PROMISE_MANAGER'];
108+
} else {
109+
process.env['SELENIUM_PROMISE_MANAGER'] = initial;
110+
}
111+
}
112+
})();
113+
114+
/**
115+
* Wraps a function on Mocha's BDD interface so it runs inside a
116+
* webdriver.promise.ControlFlow and waits for the flow to complete before
117+
* continuing.
118+
* @param {!Function} globalFn The function to wrap.
119+
* @return {!Function} The new function.
120+
*/
121+
function wrapped(globalFn) {
122+
return function() {
123+
if (arguments.length === 1) {
124+
return globalFn(makeAsyncTestFn(arguments[0]));
125+
126+
} else if (arguments.length === 2) {
127+
return globalFn(arguments[0], makeAsyncTestFn(arguments[1]));
128+
129+
} else {
130+
throw Error('Invalid # arguments: ' + arguments.length);
131+
}
132+
};
133+
}
134+
135+
/**
136+
* Wraps a function so that all passed arguments are ignored.
137+
* @param {!Function} fn The function to wrap.
138+
* @return {!Function} The wrapped function.
139+
*/
140+
function seal(fn) {
141+
return function() {
142+
fn();
143+
};
144+
}
145+
146+
/**
147+
* Make a wrapper to invoke caller's test function, fn. Run the test function
148+
* within a ControlFlow.
149+
*
150+
* Should preserve the semantics of Mocha's Runnable.prototype.run (See
151+
* https://github.com/mochajs/mocha/blob/master/lib/runnable.js#L192)
152+
*
153+
* @param {!Function} fn
154+
* @return {!Function}
155+
*/
156+
function makeAsyncTestFn(fn) {
157+
var isAsync = fn.length > 0;
158+
var isGenerator = promise.isGenerator(fn);
159+
if (isAsync && isGenerator) {
160+
throw new TypeError(
161+
'generator-based tests must not take a callback; for async testing,'
162+
+ ' return a promise (or yield on a promise)');
163+
}
164+
165+
var ret = /** @type {function(this: mocha.Context)}*/ function(done) {
166+
var self = this;
167+
var runTest = function(resolve, reject) {
168+
try {
169+
if (self.isAsync) {
170+
fn.call(self, function(err) { err ? reject(err) : resolve(); });
171+
} else if (self.isGenerator) {
172+
resolve(promise.consume(fn, self));
173+
} else {
174+
resolve(fn.call(self));
175+
}
176+
} catch (ex) {
177+
reject(ex);
178+
}
179+
};
180+
181+
if (!promise.USE_PROMISE_MANAGER) {
182+
new promise.Promise(runTest).then(seal(done), done);
183+
return;
184+
}
185+
186+
var runnable = this.runnable();
187+
var mochaCallback = runnable.callback;
188+
runnable.callback = function() {
189+
flow.reset();
190+
return mochaCallback.apply(this, arguments);
191+
};
192+
193+
flow.execute(function controlFlowExecute() {
194+
return new promise.Promise(function(fulfill, reject) {
195+
return runTest(fulfill, reject);
196+
}, flow);
197+
}, runnable.fullTitle()).then(seal(done), done);
198+
};
199+
200+
ret.toString = function() {
201+
return fn.toString();
202+
};
203+
204+
return ret;
205+
}

lib/selenium-webdriver/webdriver.js

-9
Original file line numberDiff line numberDiff line change
@@ -415,15 +415,6 @@ webdriver.WebElement.prototype.getDriver = function() {};
415415
*/
416416
webdriver.WebElement.prototype.getId = function() {};
417417

418-
419-
/**
420-
* Returns the raw ID string ID for this element.
421-
* @returns {!webdriver.promise.Promise<string>} A promise that resolves to this
422-
* element's raw ID as a string value.
423-
*/
424-
webdriver.WebElement.prototype.getRawId = function() {};
425-
426-
427418
/**
428419
* Returns a promise for the web element's serialized representation.
429420
*

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@
2020
"chalk": "^1.1.3",
2121
"glob": "^7.0.3",
2222
"jasmine": "2.4.1",
23-
"jasminewd2": "0.0.10",
23+
"jasminewd2": "0.1.0-beta.0",
2424
"optimist": "~0.6.0",
2525
"q": "1.4.1",
2626
"saucelabs": "~1.3.0",
27-
"selenium-webdriver": "2.53.3",
27+
"selenium-webdriver": "3.0.1",
2828
"source-map-support": "~0.4.0",
2929
"webdriver-manager": "^10.3.0"
3030
},

spec/basic/elements_spec.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -463,19 +463,19 @@ describe('ElementArrayFinder', function() {
463463
]);
464464
});
465465

466-
it('should map and resolve multiple promises', function() {
466+
fit('should map and resolve multiple promises', function() {
467467
browser.get('index.html#/form');
468468
var labels = element.all(by.css('#animals ul li')).map(function(elm) {
469469
return {
470470
text: elm.getText(),
471-
inner: elm.getInnerHtml()
471+
tagName: elm.getTagName()
472472
};
473473
});
474474

475475
var newExpected = function(expectedLabel) {
476476
return {
477477
text: expectedLabel,
478-
inner: expectedLabel
478+
tagName: 'li'
479479
};
480480
};
481481

spec/basic/expected_conditions_spec.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ describe('expected conditions', function() {
1111

1212
var alertButton = $('#alertbutton');
1313
alertButton.click();
14-
browser.wait(protractor.ExpectedConditions.alertIsPresent(), 1000);
15-
14+
browser.wait(protractor.ExpectedConditions.alertIsPresent(), 5000);
1615
browser.switchTo().alert().accept();
1716
});
1817

0 commit comments

Comments
 (0)