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

Commit

Permalink
deps(selenium-webdriver): upgrade to selenium 3 (#3781)
Browse files Browse the repository at this point in the history
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 `jasminewd2@0.1.0-beta.0`.
- 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
  • Loading branch information
cnishina authored and juliemr committed Dec 29, 2016
1 parent eb31c9c commit a3e8b43
Show file tree
Hide file tree
Showing 18 changed files with 211 additions and 113 deletions.
6 changes: 3 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
language: node_js
sudo: false
node_js:
- "4"
- "6"
- "7"

env:
global:
Expand All @@ -24,9 +24,9 @@ matrix:
- env: "JOB=bstack"
exclude:
- env: JOB=smoke
node_js: "6"
node_js: "7"
- env: JOB=bstack
node_js: "6"
node_js: "7"

addons:
apt:
Expand Down
4 changes: 2 additions & 2 deletions circle.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
machine:
node:
version: 6.9.1
environment:
# Fix issue with selenium-server in containers.
# See http://github.com/SeleniumHQ/docker-selenium/issues/87
DBUS_SESSION_BUS_ADDRESS: /dev/null
post:
- npm install -g npm@3

dependencies:
override:
Expand Down
4 changes: 2 additions & 2 deletions lib/debugger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ export class DebugHelper {
});

let pausePromise = flow.execute(() => {
return debuggerReadyPromise.then(() => {
return debuggerReadyPromise.promise.then(() => {
// Necessary for backward compatibility with node < 0.12.0
return this.browserUnderDebug_.executeScriptWithDescription('', 'empty debugger hook');
});
Expand Down Expand Up @@ -255,7 +255,7 @@ export class DebugHelper {
}
});

return doneDeferred.then(
return doneDeferred.promise.then(
() => {
this.debuggerValidated_ = true;
},
Expand Down
4 changes: 2 additions & 2 deletions lib/debugger/debuggerCommons.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ exports.attachDebugger = function(pid, opt_port) {
client.once('ready', function() {
client.setBreakpoint({
type: 'scriptRegExp',
target: '.*command\.js', //jshint ignore:line
line: 250
target: 'lib/http\.js', //jshint ignore:line
line: 432
}, function() {
process.send('ready');
client.reqContinue(function() {
Expand Down
8 changes: 5 additions & 3 deletions lib/driverProviders/attachSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@
*/
import * as q from 'q';
import {WebDriver} from 'selenium-webdriver';
import * as executors from 'selenium-webdriver/executors';

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

import {DriverProvider} from './driverProvider';

const http = require('selenium-webdriver/http');

let logger = new Logger('attachSession');

export class AttachSession extends DriverProvider {
Expand All @@ -38,8 +39,9 @@ export class AttachSession extends DriverProvider {
* @return {WebDriver} webdriver instance
*/
getNewDriver(): WebDriver {
let executor = executors.createExecutor(this.config_.seleniumAddress);
let newDriver = WebDriver.attachToSession(executor, this.config_.seleniumSessionId);
var httpClient = new http.HttpClient(this.config_.seleniumAddress);
var executor = new http.Executor(httpClient);
var newDriver = WebDriver.attachToSession(executor, this.config_.seleniumSessionId);
this.drivers_.push(newDriver);
return newDriver;
}
Expand Down
10 changes: 7 additions & 3 deletions lib/driverProviders/direct.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,18 @@ export class Direct extends DriverProvider {
'. Run \'webdriver-manager update\' to download binaries.');
}

let service = new ChromeServiceBuilder(chromeDriverFile).build();
driver = new ChromeDriver(new Capabilities(this.config_.capabilities), service);
let chromeService = new ChromeServiceBuilder(chromeDriverFile).build();
driver = ChromeDriver.createSession(new Capabilities(this.config_.capabilities), chromeService);
break;
case 'firefox':
if (this.config_.firefoxPath) {
this.config_.capabilities['firefox_binary'] = this.config_.firefoxPath;
}
driver = new FirefoxDriver(this.config_.capabilities);

// TODO(cnishina): Add in a service builder with marionette. Direct connect
// currently supports FF legacy version 47.
driver =
FirefoxDriver.createSession(new Capabilities(this.config_.capabilities));
break;
default:
throw new BrowserError(
Expand Down
14 changes: 7 additions & 7 deletions lib/element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ export interface WebdriverWebElement extends WebElement {}

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

/**
Expand Down Expand Up @@ -419,8 +419,8 @@ export class ElementArrayFinder extends WebdriverWebElement {
(arr: WebElement[]) => {
return arr.length;
},
(err: IError) => {
if (err.code && err.code == (new wderror.NoSuchSessionError() as any).code) {
(err: Error) => {
if (err instanceof wderror.NoSuchElementError) {
return 0;
} else {
throw err;
Expand Down Expand Up @@ -1065,15 +1065,15 @@ export class ElementFinder extends WebdriverWebElement {
return true; // is present, whether it is enabled or not
},
(err: any) => {
if (err.code == (new wderror.StaleElementReferenceError() as any).code) {
if (err instanceof wderror.StaleElementReferenceError) {
return false;
} else {
throw err;
}
});
},
(err: any) => {
if (err.code == (new wderror.NoSuchElementError() as any).code) {
(err: Error) => {
if (err instanceof wderror.NoSuchElementError) {
return false;
} else {
throw err;
Expand Down
2 changes: 1 addition & 1 deletion lib/expectedConditions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ export class ProtractorExpectedConditions {
return true;
},
(err: any) => {
if (err.code == (new wderror.NoSuchAlertError() as any).code) {
if (err instanceof wderror.NoSuchAlertError) {
return false;
} else {
throw err;
Expand Down
132 changes: 118 additions & 14 deletions lib/frameworks/mocha.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
var q = require('q');
var promise = require('selenium-webdriver').promise;

/**
* Execute the Runner's test cases through Mocha.
Expand All @@ -17,19 +18,14 @@ exports.run = function(runner, specs) {
// wait until then to load mocha-webdriver adapters as well.
mocha.suite.on('pre-require', function() {
try {
// We need to re-wrap all of the global functions, which selenium-webdriver/
// testing only does when it is required. So first we must remove it from
// the cache.
delete require.cache[require.resolve('selenium-webdriver/testing')];
var mochaAdapters = require('selenium-webdriver/testing');
global.after = mochaAdapters.after;
global.afterEach = mochaAdapters.afterEach;
global.before = mochaAdapters.before;
global.beforeEach = mochaAdapters.beforeEach;

global.it = mochaAdapters.it;
global.it.only = global.iit = mochaAdapters.iit;
global.it.skip = global.xit = mochaAdapters.xit;
global.after = wrapped(global.after);
global.afterEach = wrapped(global.afterEach);
global.before = wrapped(global.before);
global.beforeEach = wrapped(global.beforeEach);

global.it = wrapped(global.it);
global.it.only = wrapped(global.iit);
global.it.skip = wrapped(global.xit);
} catch (err) {
deferred.reject(err);
}
Expand All @@ -38,7 +34,6 @@ exports.run = function(runner, specs) {
mocha.loadFiles();

runner.runTestPreparer().then(function() {

specs.forEach(function(file) {
mocha.addFile(file);
});
Expand Down Expand Up @@ -99,3 +94,112 @@ exports.run = function(runner, specs) {

return deferred.promise;
};



var flow = (function() {
var initial = process.env['SELENIUM_PROMISE_MANAGER'];
try {
process.env['SELENIUM_PROMISE_MANAGER'] = '1';
return promise.controlFlow();
} finally {
if (initial === undefined) {
delete process.env['SELENIUM_PROMISE_MANAGER'];
} else {
process.env['SELENIUM_PROMISE_MANAGER'] = initial;
}
}
})();

/**
* Wraps a function on Mocha's BDD interface so it runs inside a
* webdriver.promise.ControlFlow and waits for the flow to complete before
* continuing.
* @param {!Function} globalFn The function to wrap.
* @return {!Function} The new function.
*/
function wrapped(globalFn) {
return function() {
if (arguments.length === 1) {
return globalFn(makeAsyncTestFn(arguments[0]));

} else if (arguments.length === 2) {
return globalFn(arguments[0], makeAsyncTestFn(arguments[1]));

} else {
throw Error('Invalid # arguments: ' + arguments.length);
}
};
}

/**
* Wraps a function so that all passed arguments are ignored.
* @param {!Function} fn The function to wrap.
* @return {!Function} The wrapped function.
*/
function seal(fn) {
return function() {
fn();
};
}

/**
* Make a wrapper to invoke caller's test function, fn. Run the test function
* within a ControlFlow.
*
* Should preserve the semantics of Mocha's Runnable.prototype.run (See
* https://github.com/mochajs/mocha/blob/master/lib/runnable.js#L192)
*
* @param {!Function} fn
* @return {!Function}
*/
function makeAsyncTestFn(fn) {
var isAsync = fn.length > 0;
var isGenerator = promise.isGenerator(fn);
if (isAsync && isGenerator) {
throw new TypeError(
'generator-based tests must not take a callback; for async testing,'
+ ' return a promise (or yield on a promise)');
}

var ret = /** @type {function(this: mocha.Context)}*/ function(done) {
var self = this;
var runTest = function(resolve, reject) {
try {
if (self.isAsync) {
fn.call(self, function(err) { err ? reject(err) : resolve(); });
} else if (self.isGenerator) {
resolve(promise.consume(fn, self));
} else {
resolve(fn.call(self));
}
} catch (ex) {
reject(ex);
}
};

if (!promise.USE_PROMISE_MANAGER) {
new promise.Promise(runTest).then(seal(done), done);
return;
}

var runnable = this.runnable();
var mochaCallback = runnable.callback;
runnable.callback = function() {
flow.reset();
return mochaCallback.apply(this, arguments);
};

flow.execute(function controlFlowExecute() {
return new promise.Promise(function(fulfill, reject) {
return runTest(fulfill, reject);
}, flow);
}, runnable.fullTitle()).then(seal(done), done);
};

ret.toString = function() {
return fn.toString();
};

return ret;
}
9 changes: 0 additions & 9 deletions lib/selenium-webdriver/webdriver.js
Original file line number Diff line number Diff line change
Expand Up @@ -415,15 +415,6 @@ webdriver.WebElement.prototype.getDriver = function() {};
*/
webdriver.WebElement.prototype.getId = function() {};


/**
* Returns the raw ID string ID for this element.
* @returns {!webdriver.promise.Promise<string>} A promise that resolves to this
* element's raw ID as a string value.
*/
webdriver.WebElement.prototype.getRawId = function() {};


/**
* Returns a promise for the web element's serialized representation.
*
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@
"chalk": "^1.1.3",
"glob": "^7.0.3",
"jasmine": "2.4.1",
"jasminewd2": "0.0.10",
"jasminewd2": "0.1.0-beta.0",
"optimist": "~0.6.0",
"q": "1.4.1",
"saucelabs": "~1.3.0",
"selenium-webdriver": "2.53.3",
"selenium-webdriver": "3.0.1",
"source-map-support": "~0.4.0",
"webdriver-manager": "^10.3.0"
},
Expand Down
6 changes: 3 additions & 3 deletions spec/basic/elements_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -463,19 +463,19 @@ describe('ElementArrayFinder', function() {
]);
});

it('should map and resolve multiple promises', function() {
fit('should map and resolve multiple promises', function() {
browser.get('index.html#/form');
var labels = element.all(by.css('#animals ul li')).map(function(elm) {
return {
text: elm.getText(),
inner: elm.getInnerHtml()
tagName: elm.getTagName()
};
});

var newExpected = function(expectedLabel) {
return {
text: expectedLabel,
inner: expectedLabel
tagName: 'li'
};
};

Expand Down
3 changes: 1 addition & 2 deletions spec/basic/expected_conditions_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ describe('expected conditions', function() {

var alertButton = $('#alertbutton');
alertButton.click();
browser.wait(protractor.ExpectedConditions.alertIsPresent(), 1000);

browser.wait(protractor.ExpectedConditions.alertIsPresent(), 5000);
browser.switchTo().alert().accept();
});

Expand Down
Loading

0 comments on commit a3e8b43

Please sign in to comment.