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

Commit 9465b9f

Browse files
sjelinjuliemr
authored andcommitted
feat(mobile): add extended wd commands for appium (#3860)
Also had to make some minor changes to the website to handle longer inheritance chains Closes #1940
1 parent 8196059 commit 9465b9f

File tree

8 files changed

+121
-27
lines changed

8 files changed

+121
-27
lines changed

gulpfile.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ gulp.task('webdriver:update', function(done) {
7272
gulp.task('jshint', function(done) {
7373
runSpawn(done, 'node', ['node_modules/jshint/bin/jshint', '-c',
7474
'.jshintrc', 'lib', 'spec', 'scripts',
75-
'--exclude=lib/selenium-webdriver/**/*.js,spec/dependencyTest/*.js,' +
76-
'spec/install/**/*.js']);
75+
'--exclude=lib/selenium-webdriver/**/*.js,lib/webdriver-js-extender/**/*.js,' +
76+
'spec/dependencyTest/*.js,spec/install/**/*.js']);
7777
});
7878

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

lib/browser.ts

+23-9
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

+3-3
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ webdriver.TouchSequence = function() {};
2525
// //
2626
// // webdriver.WebDriver
2727
// //
28-
// //////////////////////////////////////////////////////////////////////////////
28+
// /////////////////////////////////////////////////////////////////////////////
2929
/**
3030
* Protractor's `browser` object is a wrapper for `selenium-webdriver` WebDriver.
3131
* It inherits call of WebDriver's methods, but only the methods most useful to
@@ -352,11 +352,11 @@ webdriver.WebDriver.prototype.takeScreenshot = function() {};
352352
*/
353353
webdriver.WebDriver.prototype.switchTo = function() {}
354354

355-
// //////////////////////////////////////////////////////////////////////////////
355+
// /////////////////////////////////////////////////////////////////////////////
356356
// //
357357
// // webdriver.WebElement
358358
// //
359-
// //////////////////////////////////////////////////////////////////////////////
359+
// /////////////////////////////////////////////////////////////////////////////
360360
//
361361
//
362362
//

lib/webdriver-js-extender/index.js

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
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+
* ***If you are not using an appium server, `browser` may sometimes inherit
24+
* directly from a normal `WebDriver` instance, and thus not inherit any of
25+
* the extra methods defined by `webdriver-js-extender`. Even when `browser`
26+
* does inherit from `ExtendedWebDriver`, these extra methods will only work if
27+
* your server implements the Appium API.***
28+
*
29+
* More information about `webdriver-js-extender` can be found on the [GitHub
30+
* repo](https://github.com/angular/webdriver-js-extender).
31+
* @alias ExtendedWebDriver
32+
* @constructor
33+
* @extends {webdriver.WebDriver}
34+
*/
35+
webdriver_extensions.ExtendedWebDriver = function() {};
36+
37+
/**
38+
* Schedules a command to retrieve the network connection type.
39+
*
40+
* Network connection types are a bitmask with:
41+
* 1 -> airplane mode
42+
* 2 -> wifi
43+
* 4 -> data
44+
*
45+
* @example
46+
* expect(browser.getNetworkConnection()).toBe(6); //Expect wifi and data on
47+
*
48+
* @returns {!webdriver.promise.Promise.<number>} A promise that will be
49+
* resolved with the current network connection type.
50+
*/
51+
webdriver_extensions.ExtendedWebDriver.prototype.getNetworkConnection = function() {};
52+
53+
/**
54+
* Schedules a command to set the network connection type.
55+
*
56+
* Network connection types are a bitmask with:
57+
* 1 -> airplane mode
58+
* 2 -> wifi
59+
* 4 -> data
60+
*
61+
* @example
62+
* browser.setNetworkConnection(1); //Turn on airplane mode
63+
* expect(browser.getNetworkConnection()).toBe(1);
64+
*
65+
* @param {number} type The type to set the network connection to.
66+
* @returns {!webdriver.promise.Promise.<void>} A promise that will be
67+
* resolved when the network connection type is set.
68+
*/
69+
webdriver_extensions.ExtendedWebDriver.prototype.setNetworkConnection = function(type) {};

package.json

+2-1
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.1.0"
29+
"webdriver-manager": "^11.1.0",
30+
"webdriver-js-extender": "^0.2.2"
3031
},
3132
"devDependencies": {
3233
"@types/chalk": "^0.4.28",

website/docgen/dgeni-config.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ myPackage.config(function(readFilesProcessor, templateFinder, writeFilesProcesso
7777
{include: 'built/locators.js'},
7878
{include: 'built/expectedConditions.js'},
7979
{include: 'lib/selenium-webdriver/locators.js'},
80-
{include: 'lib/selenium-webdriver/webdriver.js'}
80+
{include: 'lib/selenium-webdriver/webdriver.js'},
81+
{include: 'lib/webdriver-js-extender/index.js'}
8182
];
8283

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

website/js/api-controller.js

+11-9
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

+9-2
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)