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

Commit 5a2add8

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 8952eab commit 5a2add8

File tree

9 files changed

+126
-30
lines changed

9 files changed

+126
-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,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';
@@ -34,7 +35,7 @@ for (let foo in require('selenium-webdriver')) {
3435

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

67+
export class AbstractExtendedWebDriver extends AbstractWebDriver {
68+
getNetworkConnection: () => webdriver.promise.Promise<number>;
69+
setNetworkConnection: (type: number) => webdriver.promise.Promise<void>;
70+
}
71+
6672
/**
6773
* Mix a function from one object onto another. The function will still be
6874
* called in the context of the original object. Any arguments of type
@@ -115,15 +121,15 @@ function buildElementHelper(browser: ProtractorBrowser): ElementHelper {
115121
/**
116122
* @alias browser
117123
* @constructor
118-
* @extends {webdriver.WebDriver}
124+
* @extends {webdriver_extensions.ExtendedWebDriver}
119125
* @param {webdriver.WebDriver} webdriver
120126
* @param {string=} opt_baseUrl A base URL to run get requests against.
121127
* @param {string=} opt_rootElement Selector element that has an ng-app in
122128
* scope.
123129
* @param {boolean=} opt_untrackOutstandingTimeouts Whether Protractor should
124130
* stop tracking outstanding $timeouts.
125131
*/
126-
export class ProtractorBrowser extends Webdriver {
132+
export class ProtractorBrowser extends AbstractExtendedWebDriver {
127133
/**
128134
* @type {ProtractorBy}
129135
*/
@@ -138,9 +144,9 @@ export class ProtractorBrowser extends Webdriver {
138144
* The wrapped webdriver instance. Use this to interact with pages that do
139145
* not contain Angular (such as a log-in screen).
140146
*
141-
* @type {webdriver.WebDriver}
147+
* @type {webdriver_extensions.ExtendedWebDriver}
142148
*/
143-
driver: WebDriver;
149+
driver: ExtendedWebDriver;
144150

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

283297
// Mix all other driver functionality into Protractor.
284298
Object.getOwnPropertyNames(WebDriver.prototype).forEach(method => {
285-
if (!this[method] && typeof(webdriverInstance as any)[method] === 'function') {
299+
if (!this[method] && typeof(extendWDInstance as any)[method] === 'function') {
286300
if (methodsToSync.indexOf(method) !== -1) {
287-
ptorMixin(this, webdriverInstance, method, this.waitForAngular.bind(this));
301+
ptorMixin(this, extendWDInstance, method, this.waitForAngular.bind(this));
288302
} else {
289-
ptorMixin(this, webdriverInstance, method);
303+
ptorMixin(this, extendWDInstance, method);
290304
}
291305
}
292306
});
293307

294-
this.driver = webdriverInstance;
308+
this.driver = extendWDInstance;
295309
this.element = buildElementHelper(this);
296310
this.$ = build$(this.element, By);
297311
this.$$ = build$$(this.element, By);

lib/runner.ts

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

68
import {ProtractorBrowser} from './browser';
79
import {Config} from './config';
@@ -98,6 +100,13 @@ export class Runner extends EventEmitter {
98100
* 5) try to find the seleniumServerJar in protractor/selenium
99101
*/
100102
loadDriverProvider_(config: Config) {
103+
// `webdriver-js-extender` needs to overwrite `DeferredExecutor` and some
104+
// associated functions so that it can define custom commands. In version
105+
// 3.x of `selenium-webdriver`, this will no longer be necessary and will
106+
// have to be removed.
107+
patch(
108+
require('selenium-webdriver/lib/command'), require('selenium-webdriver/executors'),
109+
require('selenium-webdriver/http'));
101110
this.config_ = config;
102111
if (this.config_.directConnect) {
103112
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.3.0"
29+
"webdriver-manager": "^10.3.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)