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

Commit da69654

Browse files
committed
feat(mobile): add extended wd commands for appium
Had to make some minor changes to the website to handle longer inheritance chains
1 parent 742f264 commit da69654

File tree

10 files changed

+128
-28
lines changed

10 files changed

+128
-28
lines changed

gulpfile.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ gulp.task('webdriver:update', function(done) {
6161

6262
gulp.task('jshint', function(done) {
6363
runSpawn(done, 'node', ['node_modules/jshint/bin/jshint', 'lib', 'spec', 'scripts',
64-
'--exclude=lib/selenium-webdriver/**/*.js,spec/dependencyTest/*.js,' +
65-
'spec/install/**/*.js']);
64+
'--exclude=lib/selenium-webdriver/**/*.js,lib/webdriver-js-extender/**/*.js,' +
65+
'spec/dependencyTest/*.js,spec/install/**/*.js']);
6666
});
6767

6868
gulp.task('format:enforce', function() {

lib/browser.ts

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {ActionSequence, By, Capabilities, Command as WdCommand, FileDetector, ICommandName, Options, promise as wdpromise, Session, TargetLocator, TouchSequence, until, WebDriver, WebElement} from 'selenium-webdriver';
22
import * as url from 'url';
3+
import {extend as extendWD, ExtendedWebDriver} from 'webdriver-js-extender';
34

45
import {DebugHelper} from './debugger';
56
import {build$, build$$, ElementArrayFinder, ElementFinder} from './element';
@@ -61,6 +62,11 @@ export class Webdriver {
6162
opt_message?: string) => wdpromise.Promise<any>;
6263
}
6364

65+
export class ExtendedWebdriver {
66+
getNetworkConnection: () => webdriver.promise.Promise<number>;
67+
setNetworkConnection: (type: number) => webdriver.promise.Promise<void>;
68+
}
69+
6470
/**
6571
* Mix a function from one object onto another. The function will still be
6672
* called in the context of the original object. Any arguments of type
@@ -114,15 +120,15 @@ function buildElementHelper(browser: ProtractorBrowser): ElementHelper {
114120
/**
115121
* @alias browser
116122
* @constructor
117-
* @extends {webdriver.WebDriver}
123+
* @extends {webdriver_extensions.ExtendedWebDriver}
118124
* @param {webdriver.WebDriver} webdriver
119125
* @param {string=} opt_baseUrl A base URL to run get requests against.
120126
* @param {string=} opt_rootElement Selector element that has an ng-app in
121127
* scope.
122128
* @param {boolean=} opt_untrackOutstandingTimeouts Whether Protractor should
123129
* stop tracking outstanding $timeouts.
124130
*/
125-
export class ProtractorBrowser extends Webdriver {
131+
export class ProtractorBrowser extends ExtendedWebdriver {
126132
/**
127133
* @type {ProtractorBy}
128134
*/
@@ -137,9 +143,9 @@ export class ProtractorBrowser extends Webdriver {
137143
* The wrapped webdriver instance. Use this to interact with pages that do
138144
* not contain Angular (such as a log-in screen).
139145
*
140-
* @type {webdriver.WebDriver}
146+
* @type {webdriver_extensions.ExtendedWebDriver}
141147
*/
142-
driver: WebDriver;
148+
driver: ExtendedWebDriver;
143149

144150
/**
145151
* Helper function for finding elements.
@@ -278,19 +284,27 @@ export class ProtractorBrowser extends Webdriver {
278284
// wait for Angular to sync up before performing the action. This does not
279285
// include functions which are overridden by protractor below.
280286
let methodsToSync = ['getCurrentUrl', 'getPageSource', 'getTitle'];
287+
let extendWDInstance: ExtendedWebDriver;
288+
try {
289+
extendWDInstance = extendWD(webdriverInstance);
290+
} catch (e) {
291+
// Probably not a driver that can be extended (e.g. gotten using
292+
// `directConnect: true` in the config)
293+
extendWDInstance = webdriverInstance as ExtendedWebDriver;
294+
}
281295

282296
// Mix all other driver functionality into Protractor.
283297
Object.getOwnPropertyNames(WebDriver.prototype).forEach(method => {
284-
if (!this[method] && typeof(webdriverInstance as any)[method] === 'function') {
298+
if (!this[method] && typeof(extendWDInstance as any)[method] === 'function') {
285299
if (methodsToSync.indexOf(method) !== -1) {
286-
ptorMixin(this, webdriverInstance, method, this.waitForAngular.bind(this));
300+
ptorMixin(this, extendWDInstance, method, this.waitForAngular.bind(this));
287301
} else {
288-
ptorMixin(this, webdriverInstance, method);
302+
ptorMixin(this, extendWDInstance, method);
289303
}
290304
}
291305
});
292306

293-
this.driver = webdriverInstance;
307+
this.driver = extendWDInstance;
294308
this.element = buildElementHelper(this);
295309
this.$ = build$(this.element, By);
296310
this.$$ = build$$(this.element, By);
@@ -972,4 +986,7 @@ export class ProtractorBrowser extends Webdriver {
972986
untrackOutstandingTimeouts?: boolean): ProtractorBrowser {
973987
return new ProtractorBrowser(webdriver, baseUrl, rootElement, untrackOutstandingTimeouts);
974988
}
989+
990+
// Extended webdriver methods
991+
975992
}

lib/runner.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import {EventEmitter} from 'events';
22
import * as q from 'q';
33
import * as util from 'util';
4+
// TODO(sjelin): patch() will no longer be needed with `selenium-webdriver` 3.x
5+
import {patch} from 'webdriver-js-extender';
46

57
import {ProtractorBrowser} from './browser';
68
import {Config} from './config';
@@ -99,6 +101,13 @@ export class Runner extends EventEmitter {
99101
* 5) try to find the seleniumServerJar in protractor/selenium
100102
*/
101103
loadDriverProvider_(config: Config) {
104+
// `webdriver-js-extender` needs to overwrite `DeferredExecutor` and some
105+
// associated functions so that it can define custom commands. In version
106+
// 3.x of `selenium-webdriver`, this will no longer be necessary and will
107+
// have to be removed.
108+
patch(
109+
require('selenium-webdriver/lib/command'), require('selenium-webdriver/executors'),
110+
require('selenium-webdriver/http'));
102111
this.config_ = config;
103112
if (this.config_.directConnect) {
104113
this.driverprovider_ = new Direct(this.config_);

lib/selenium-webdriver/webdriver.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77

88
goog.provide('webdriver');
99

10-
// //////////////////////////////////////////////////////////////////////////////
10+
// /////////////////////////////////////////////////////////////////////////////
1111
// //
1212
// // webdriver.WebDriver
1313
// //
14-
// //////////////////////////////////////////////////////////////////////////////
14+
// /////////////////////////////////////////////////////////////////////////////
1515
/**
1616
* Protractor's `browser` object is a wrapper for `selenium-webdriver` WebDriver.
1717
* It inherits call of WebDriver's methods, but only the methods most useful to
@@ -318,11 +318,11 @@ webdriver.WebDriver.prototype.takeScreenshot = function() {};
318318
*/
319319
webdriver.WebDriver.prototype.switchTo = function() {}
320320

321-
// //////////////////////////////////////////////////////////////////////////////
321+
// /////////////////////////////////////////////////////////////////////////////
322322
// //
323323
// // webdriver.WebElement
324324
// //
325-
// //////////////////////////////////////////////////////////////////////////////
325+
// /////////////////////////////////////////////////////////////////////////////
326326
//
327327
//
328328
//

lib/webdriver-js-extender/index.js

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Used to provide better protractor documentation for methods given by
2+
// `webdriver-js-extender`.
3+
4+
/**
5+
* @fileoverview Extra methods provided by webdriver-js-extender.
6+
*/
7+
8+
goog.provide('webdriver_extensions');
9+
10+
// /////////////////////////////////////////////////////////////////////////////
11+
// //
12+
// // webdriver_extensions.ExtendedWebDriver
13+
// //
14+
// /////////////////////////////////////////////////////////////////////////////
15+
/**
16+
* Protractor's `browser` object is a wrapper for an instance of
17+
* `ExtendedWebDriver`, provided by `webdriver-js-extender`, which itself is
18+
* just an instance of `selenium-webdriver`'s WebDriver with some extra methods
19+
* added in. The `browser` object inherits all of WebDriver's and
20+
* ExtendedWebDriver's methods, but only the methods most useful to Protractor
21+
* users are documented here.
22+
*
23+
* More information about `webdriver-js-extender` can be found on the [GitHub
24+
* repo](https://github.com/angular/webdriver-js-extender).
25+
* @alias ExtendedWebDriver
26+
* @constructor
27+
* @extends {webdriver.WebDriver}
28+
*/
29+
webdriver_extensions.ExtendedWebDriver = function() {};
30+
31+
/**
32+
* Schedules a command to retrieve the network connection type.
33+
*
34+
* Network connection types are a bitmask with:
35+
* 1 -> airplane mode
36+
* 2 -> wifi
37+
* 4 -> data
38+
*
39+
* @example
40+
* expect(browser.getNetworkConnection()).toBe(6); //Expect wifi and data on
41+
*
42+
* @returns {!webdriver.promise.Promise.<number>} A promise that will be
43+
* resolved with the current network connection type.
44+
*/
45+
webdriver_extensions.ExtendedWebDriver.prototype.getNetworkConnection = function() {};
46+
47+
/**
48+
* Schedules a command to set the network connection type.
49+
*
50+
* Network connection types are a bitmask with:
51+
* 1 -> airplane mode
52+
* 2 -> wifi
53+
* 4 -> data
54+
*
55+
* @example
56+
* browser.setNetworkConnection(1); //Turn on airplane mode
57+
* expect(browser.getNetworkConnection()).toBe(1);
58+
*
59+
* @param {number} type The type to set the network connection to.
60+
* @returns {!webdriver.promise.Promise.<void>} A promise that will be
61+
* resolved when the network connection type is set.
62+
*/
63+
webdriver_extensions.ExtendedWebDriver.prototype.setNetworkConnection = function(type) {};

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
"saucelabs": "~1.3.0",
2727
"selenium-webdriver": "2.53.3",
2828
"source-map-support": "~0.4.0",
29-
"webdriver-manager": "^10.2.8"
29+
"webdriver-manager": "^10.2.8",
30+
"webdriver-js-extender": "^0.2.2"
3031
},
3132
"devDependencies": {
3233
"@types/chalk": "^0.4.28",

tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"jasmine", "node",
1313
"chalk", "glob", "minimatch",
1414
"minimist", "optimist", "q",
15-
"selenium-webdriver"
15+
"selenium-webdriver", "es6-promise"
1616
]
1717
},
1818
"exclude": [

website/docgen/dgeni-config.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ myPackage.config(function(readFilesProcessor, templateFinder, writeFilesProcesso
7676
{include: 'built/locators.js'},
7777
{include: 'built/expectedConditions.js'},
7878
{include: 'lib/selenium-webdriver/locators.js'},
79-
{include: 'lib/selenium-webdriver/webdriver.js'}
79+
{include: 'lib/selenium-webdriver/webdriver.js'},
80+
{include: 'lib/webdriver-js-extender/index.js'}
8081
];
8182

8283
// Add a folder to search for our own templates to use when rendering docs

website/js/api-controller.js

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -250,16 +250,18 @@
250250
// Remove braces from {type}.
251251
var parentName = item.extends.replace(/[{}]/g, '');
252252
var nameExpr = new RegExp(parentName + '\\.prototype');
253+
var parent = self.itemsByName[parentName];
253254

254-
// Find all the parent functions.
255-
item.base = {
256-
name: parentName,
257-
items: _.filter(list, function(item) {
258-
return item.name && item.name.match(nameExpr);
259-
})
260-
};
261-
if (self.itemsByName[parentName]) {
262-
self.itemsByName[parentName].extension = true;
255+
if (parent) {
256+
item.base = parent;
257+
parent.extension = true;
258+
} else {
259+
item.base = {
260+
name: parentName,
261+
children: _.filter(list, function(item) {
262+
return item.name && item.name.match(nameExpr);
263+
}),
264+
};
263265
}
264266
});
265267
};

website/partials/api.html

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,9 +173,16 @@ <h4>Functions</h4>
173173

174174
<!-- Extends -->
175175
<div ng-if="currentItem.extends">
176-
<h4>Extends {{currentItem.base.name}}</h4>
176+
<h4>Extends {{currentItem.base.title}}</h4>
177177

178-
<div ptor-function-list="currentItem.base.items"></div>
178+
<div ptor-function-list="currentItem.base.children"></div>
179+
180+
<!-- Extension Extends -->
181+
<div ng-if="currentItem.base.extends">
182+
<h4>Extends {{currentItem.base.base.title}} (via {{currentItem.base.title}})</h4>
183+
184+
<div ptor-function-list="currentItem.base.base.children"></div>
185+
</div>
179186
</div>
180187
</div>
181188
</div>

0 commit comments

Comments
 (0)