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

Commit

Permalink
feat(mobile): add extended wd commands for appium (#3860)
Browse files Browse the repository at this point in the history
Also had to make some minor changes to the website to handle longer inheritance
chains

Closes #1940
  • Loading branch information
sjelin authored and juliemr committed Dec 22, 2016
1 parent 57ee98d commit 70ce185
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 27 deletions.
4 changes: 2 additions & 2 deletions gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ gulp.task('webdriver:update', function(done) {
gulp.task('jshint', function(done) {
runSpawn(done, 'node', ['node_modules/jshint/bin/jshint', '-c',
'.jshintrc', 'lib', 'spec', 'scripts',
'--exclude=lib/selenium-webdriver/**/*.js,spec/dependencyTest/*.js,' +
'spec/install/**/*.js']);
'--exclude=lib/selenium-webdriver/**/*.js,lib/webdriver-js-extender/**/*.js,' +
'spec/dependencyTest/*.js,spec/install/**/*.js']);
});

gulp.task('format:enforce', function() {
Expand Down
32 changes: 23 additions & 9 deletions lib/browser.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {BPClient} from 'blocking-proxy';
import {ActionSequence, By, Capabilities, Command as WdCommand, FileDetector, ICommandName, Options, promise as wdpromise, Session, TargetLocator, TouchSequence, until, WebDriver, WebElement} from 'selenium-webdriver';
import * as url from 'url';
import {extend as extendWD, ExtendedWebDriver} from 'webdriver-js-extender';

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

// Explicitly define webdriver.WebDriver
// TODO: extend WebDriver from selenium-webdriver typings
export class Webdriver {
export class AbstractWebDriver {
actions: () => ActionSequence;
call:
(fn: (...var_args: any[]) => any, opt_scope?: any,
Expand Down Expand Up @@ -64,6 +65,11 @@ export class Webdriver {
opt_message?: string) => wdpromise.Promise<any>;
}

export class AbstractExtendedWebDriver extends AbstractWebDriver {
getNetworkConnection: () => wdpromise.Promise<number>;
setNetworkConnection: (type: number) => wdpromise.Promise<void>;
}

/**
* Mix a function from one object onto another. The function will still be
* called in the context of the original object. Any arguments of type
Expand Down Expand Up @@ -116,15 +122,15 @@ function buildElementHelper(browser: ProtractorBrowser): ElementHelper {
/**
* @alias browser
* @constructor
* @extends {webdriver.WebDriver}
* @extends {webdriver_extensions.ExtendedWebDriver}
* @param {webdriver.WebDriver} webdriver
* @param {string=} opt_baseUrl A base URL to run get requests against.
* @param {string=} opt_rootElement Selector element that has an ng-app in
* scope.
* @param {boolean=} opt_untrackOutstandingTimeouts Whether Protractor should
* stop tracking outstanding $timeouts.
*/
export class ProtractorBrowser extends Webdriver {
export class ProtractorBrowser extends AbstractExtendedWebDriver {
/**
* @type {ProtractorBy}
*/
Expand All @@ -139,9 +145,9 @@ export class ProtractorBrowser extends Webdriver {
* The wrapped webdriver instance. Use this to interact with pages that do
* not contain Angular (such as a log-in screen).
*
* @type {webdriver.WebDriver}
* @type {webdriver_extensions.ExtendedWebDriver}
*/
driver: WebDriver;
driver: ExtendedWebDriver;

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

// Mix all other driver functionality into Protractor.
Object.getOwnPropertyNames(WebDriver.prototype).forEach(method => {
if (!this[method] && typeof(webdriverInstance as any)[method] === 'function') {
if (!this[method] && typeof(extendWDInstance as any)[method] === 'function') {
if (methodsToSync.indexOf(method) !== -1) {
ptorMixin(this, webdriverInstance, method, this.waitForAngular.bind(this));
ptorMixin(this, extendWDInstance, method, this.waitForAngular.bind(this));
} else {
ptorMixin(this, webdriverInstance, method);
ptorMixin(this, extendWDInstance, method);
}
}
});

this.driver = webdriverInstance;
this.driver = extendWDInstance;
if (opt_blockingProxyUrl) {
logger.info('Starting BP client for ' + opt_blockingProxyUrl);
this.bpClient = new BPClient(opt_blockingProxyUrl);
Expand Down
6 changes: 3 additions & 3 deletions lib/selenium-webdriver/webdriver.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ webdriver.TouchSequence = function() {};
// //
// // webdriver.WebDriver
// //
// //////////////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////////
/**
* Protractor's `browser` object is a wrapper for `selenium-webdriver` WebDriver.
* It inherits call of WebDriver's methods, but only the methods most useful to
Expand Down Expand Up @@ -352,11 +352,11 @@ webdriver.WebDriver.prototype.takeScreenshot = function() {};
*/
webdriver.WebDriver.prototype.switchTo = function() {}

// //////////////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////////
// //
// // webdriver.WebElement
// //
// //////////////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////////
//
//
//
Expand Down
69 changes: 69 additions & 0 deletions lib/webdriver-js-extender/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Used to provide better protractor documentation for methods given by
// `webdriver-js-extender`.

/**
* @fileoverview Extra methods provided by webdriver-js-extender.
*/

goog.provide('webdriver_extensions');

// /////////////////////////////////////////////////////////////////////////////
// //
// // webdriver_extensions.ExtendedWebDriver
// //
// /////////////////////////////////////////////////////////////////////////////
/**
* Protractor's `browser` object is a wrapper for an instance of
* `ExtendedWebDriver`, provided by `webdriver-js-extender`, which itself is
* just an instance of `selenium-webdriver`'s WebDriver with some extra methods
* added in. The `browser` object inherits all of WebDriver's and
* ExtendedWebDriver's methods, but only the methods most useful to Protractor
* users are documented here.
*
* ***If you are not using an appium server, `browser` may sometimes inherit
* directly from a normal `WebDriver` instance, and thus not inherit any of
* the extra methods defined by `webdriver-js-extender`. Even when `browser`
* does inherit from `ExtendedWebDriver`, these extra methods will only work if
* your server implements the Appium API.***
*
* More information about `webdriver-js-extender` can be found on the [GitHub
* repo](https://github.com/angular/webdriver-js-extender).
* @alias ExtendedWebDriver
* @constructor
* @extends {webdriver.WebDriver}
*/
webdriver_extensions.ExtendedWebDriver = function() {};

/**
* Schedules a command to retrieve the network connection type.
*
* Network connection types are a bitmask with:
* 1 -> airplane mode
* 2 -> wifi
* 4 -> data
*
* @example
* expect(browser.getNetworkConnection()).toBe(6); //Expect wifi and data on
*
* @returns {!webdriver.promise.Promise.<number>} A promise that will be
* resolved with the current network connection type.
*/
webdriver_extensions.ExtendedWebDriver.prototype.getNetworkConnection = function() {};

/**
* Schedules a command to set the network connection type.
*
* Network connection types are a bitmask with:
* 1 -> airplane mode
* 2 -> wifi
* 4 -> data
*
* @example
* browser.setNetworkConnection(1); //Turn on airplane mode
* expect(browser.getNetworkConnection()).toBe(1);
*
* @param {number} type The type to set the network connection to.
* @returns {!webdriver.promise.Promise.<void>} A promise that will be
* resolved when the network connection type is set.
*/
webdriver_extensions.ExtendedWebDriver.prototype.setNetworkConnection = function(type) {};
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@
"saucelabs": "~1.3.0",
"selenium-webdriver": "3.0.1",
"source-map-support": "~0.4.0",
"webdriver-manager": "^11.1.0"
"webdriver-manager": "^11.1.0",
"webdriver-js-extender": "^0.2.2"
},
"devDependencies": {
"@types/chalk": "^0.4.28",
Expand Down
3 changes: 2 additions & 1 deletion website/docgen/dgeni-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ myPackage.config(function(readFilesProcessor, templateFinder, writeFilesProcesso
{include: 'built/locators.js'},
{include: 'built/expectedConditions.js'},
{include: 'lib/selenium-webdriver/locators.js'},
{include: 'lib/selenium-webdriver/webdriver.js'}
{include: 'lib/selenium-webdriver/webdriver.js'},
{include: 'lib/webdriver-js-extender/index.js'}
];

// Add a folder to search for our own templates to use when rendering docs
Expand Down
20 changes: 11 additions & 9 deletions website/js/api-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -250,16 +250,18 @@
// Remove braces from {type}.
var parentName = item.extends.replace(/[{}]/g, '');
var nameExpr = new RegExp(parentName + '\\.prototype');
var parent = self.itemsByName[parentName];

// Find all the parent functions.
item.base = {
name: parentName,
items: _.filter(list, function(item) {
return item.name && item.name.match(nameExpr);
})
};
if (self.itemsByName[parentName]) {
self.itemsByName[parentName].extension = true;
if (parent) {
item.base = parent;
parent.extension = true;
} else {
item.base = {
name: parentName,
children: _.filter(list, function(item) {
return item.name && item.name.match(nameExpr);
}),
};
}
});
};
Expand Down
11 changes: 9 additions & 2 deletions website/partials/api.html
Original file line number Diff line number Diff line change
Expand Up @@ -173,9 +173,16 @@ <h4>Functions</h4>

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

<div ptor-function-list="currentItem.base.items"></div>
<div ptor-function-list="currentItem.base.children"></div>

<!-- Extension Extends -->
<div ng-if="currentItem.base.extends">
<h4>Extends {{currentItem.base.base.title}} (via {{currentItem.base.title}})</h4>

<div ptor-function-list="currentItem.base.base.children"></div>
</div>
</div>
</div>
</div>
Expand Down

0 comments on commit 70ce185

Please sign in to comment.