Skip to content

Commit 0af5ae1

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 Closes angular#1940
1 parent 98b7f5e commit 0af5ae1

File tree

8 files changed

+117
-30
lines changed

8 files changed

+117
-30
lines changed

gulpfile.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,9 @@ gulp.task('webdriver:update', function(done) {
7070
});
7171

7272
gulp.task('jshint', function(done) {
73-
runSpawn(done, 'node', ['node_modules/jshint/bin/jshint', '-c',
74-
'.jshintrc', 'lib', 'spec', 'scripts',
75-
'--exclude=lib/selenium-webdriver/**/*.js,spec/dependencyTest/*.js,' +
76-
'spec/install/**/*.js']);
73+
runSpawn(done, 'node', ['node_modules/jshint/bin/jshint', '-c', '.jshintrc', 'lib', 'spec',
74+
'scripts', '--exclude=lib/selenium-webdriver/**/*.js,lib/webdriver-js-extender/**/*.js,' +
75+
'spec/dependencyTest/*.js,spec/install/**/*.js']);
7776
});
7877

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

lib/browser.ts

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {BPClient} from 'blocking-proxy';
22
import {ActionSequence, By, Capabilities, Command as WdCommand, FileDetector, ICommandName, Options, promise as wdpromise, Session, TargetLocator, TouchSequence, until, WebDriver, WebElement} from 'selenium-webdriver';
33
import * as url from 'url';
4+
import {extend as extendWD, ExtendedWebDriver} from 'webdriver-js-extender';
45

56
import {DebugHelper} from './debugger';
67
import {build$, build$$, ElementArrayFinder, ElementFinder} from './element';
@@ -35,7 +36,7 @@ for (let foo in require('selenium-webdriver')) {
3536

3637
// Explicitly define webdriver.WebDriver
3738
// TODO: extend WebDriver from selenium-webdriver typings
38-
export class Webdriver {
39+
export class AbstractWebDriver {
3940
actions: () => ActionSequence;
4041
call:
4142
(fn: (...var_args: any[]) => any, opt_scope?: any,
@@ -64,6 +65,11 @@ export class Webdriver {
6465
opt_message?: string) => wdpromise.Promise<any>;
6566
}
6667

68+
export class AbstractExtendedWebDriver extends AbstractWebDriver {
69+
getNetworkConnection: () => wdpromise.Promise<number>;
70+
setNetworkConnection: (type: number) => wdpromise.Promise<void>;
71+
}
72+
6773
/**
6874
* Mix a function from one object onto another. The function will still be
6975
* called in the context of the original object. Any arguments of type
@@ -116,15 +122,15 @@ function buildElementHelper(browser: ProtractorBrowser): ElementHelper {
116122
/**
117123
* @alias browser
118124
* @constructor
119-
* @extends {webdriver.WebDriver}
125+
* @extends {webdriver_extensions.ExtendedWebDriver}
120126
* @param {webdriver.WebDriver} webdriver
121127
* @param {string=} opt_baseUrl A base URL to run get requests against.
122128
* @param {string=} opt_rootElement Selector element that has an ng-app in
123129
* scope.
124130
* @param {boolean=} opt_untrackOutstandingTimeouts Whether Protractor should
125131
* stop tracking outstanding $timeouts.
126132
*/
127-
export class ProtractorBrowser extends Webdriver {
133+
export class ProtractorBrowser extends AbstractExtendedWebDriver {
128134
/**
129135
* @type {ProtractorBy}
130136
*/
@@ -139,9 +145,9 @@ export class ProtractorBrowser extends Webdriver {
139145
* The wrapped webdriver instance. Use this to interact with pages that do
140146
* not contain Angular (such as a log-in screen).
141147
*
142-
* @type {webdriver.WebDriver}
148+
* @type {webdriver_extensions.ExtendedWebDriver}
143149
*/
144-
driver: WebDriver;
150+
driver: ExtendedWebDriver;
145151

146152
/**
147153
* The client used to control the BlockingProxy. If unset, BlockingProxy is
@@ -303,19 +309,27 @@ export class ProtractorBrowser extends Webdriver {
303309
// wait for Angular to sync up before performing the action. This does not
304310
// include functions which are overridden by protractor below.
305311
let methodsToSync = ['getCurrentUrl', 'getPageSource', 'getTitle'];
312+
let extendWDInstance: ExtendedWebDriver;
313+
try {
314+
extendWDInstance = extendWD(webdriverInstance);
315+
} catch (e) {
316+
// Probably not a driver that can be extended (e.g. gotten using
317+
// `directConnect: true` in the config)
318+
extendWDInstance = webdriverInstance as ExtendedWebDriver;
319+
}
306320

307321
// Mix all other driver functionality into Protractor.
308322
Object.getOwnPropertyNames(WebDriver.prototype).forEach(method => {
309-
if (!this[method] && typeof(webdriverInstance as any)[method] === 'function') {
323+
if (!this[method] && typeof(extendWDInstance as any)[method] === 'function') {
310324
if (methodsToSync.indexOf(method) !== -1) {
311-
ptorMixin(this, webdriverInstance, method, this.waitForAngular.bind(this));
325+
ptorMixin(this, extendWDInstance, method, this.waitForAngular.bind(this));
312326
} else {
313-
ptorMixin(this, webdriverInstance, method);
327+
ptorMixin(this, extendWDInstance, method);
314328
}
315329
}
316330
});
317331

318-
this.driver = webdriverInstance;
332+
this.driver = extendWDInstance;
319333
if (opt_blockingProxyUrl) {
320334
logger.info('Starting BP client for ' + opt_blockingProxyUrl);
321335
this.bpClient = new BPClient(opt_blockingProxyUrl);

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": "3.0.1",
2828
"source-map-support": "~0.4.0",
29-
"webdriver-manager": "^11.0.0"
29+
"webdriver-manager": "^11.0.0",
30+
"webdriver-js-extender": "^0.2.2"
3031
},
3132
"devDependencies": {
3233
"@types/chalk": "^0.4.28",

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)