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

feat(mobile): add extended wd commands for appium #3326

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,9 @@ 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']);
runSpawn(done, 'node', ['node_modules/jshint/bin/jshint', '-c', '.jshintrc', 'lib', 'spec',
'scripts', '--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,5 +1,6 @@
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 @@ -34,7 +35,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 @@ -63,6 +64,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 @@ -115,15 +121,15 @@ function buildElementHelper(browser: ProtractorBrowser): ElementHelper {
/**
* @alias browser
* @constructor
* @extends {webdriver.WebDriver}
* @extends {webdriver_extensions.ExtendedWebDriver}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this extends the class above and not really the webdriver_extensions

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In order for js doc to work, this is the correct type (see old version pointing to webdriver.WebDriver not Webdriver)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. Alright, that makes sense.

* @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 @@ -138,9 +144,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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cnishina are there any type implications here once we fixed definitely typed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cnishina are there any type implications here once we fixed definitely typed?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this is taken care of. This does not appear to have typing implications.


/**
* Helper function for finding elements.
Expand Down Expand Up @@ -279,19 +285,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;
this.element = buildElementHelper(this);
this.$ = build$(this.element, By);
this.$$ = build$$(this.element, By);
Expand Down
9 changes: 9 additions & 0 deletions lib/runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import {EventEmitter} from 'events';
import * as q from 'q';
import {promise as wdpromise, Session} from 'selenium-webdriver';
import * as util from 'util';
// TODO(sjelin): patch() will no longer be needed with `selenium-webdriver` 3.x
import {patch} from 'webdriver-js-extender';

import {ProtractorBrowser} from './browser';
import {Config} from './config';
Expand Down Expand Up @@ -98,6 +100,13 @@ export class Runner extends EventEmitter {
* 5) try to find the seleniumServerJar in protractor/selenium
*/
loadDriverProvider_(config: Config) {
// `webdriver-js-extender` needs to overwrite `DeferredExecutor` and some
// associated functions so that it can define custom commands. In version
// 3.x of `selenium-webdriver`, this will no longer be necessary and will
// have to be removed.
patch(
require('selenium-webdriver/lib/command'), require('selenium-webdriver/executors'),
require('selenium-webdriver/http'));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with the new types, could we import these with

import * as http from 'selenium-webdriver/http';
import * as executors from 'selenium-webdriver/executors';

?

this.config_ = config;
if (this.config_.directConnect) {
this.driverprovider_ = new Direct(this.config_);
Expand Down
8 changes: 4 additions & 4 deletions lib/selenium-webdriver/webdriver.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@

goog.provide('webdriver');

// //////////////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////////
// //
// // 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 @@ -318,11 +318,11 @@ webdriver.WebDriver.prototype.takeScreenshot = function() {};
*/
webdriver.WebDriver.prototype.switchTo = function() {}

// //////////////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////////
// //
// // webdriver.WebElement
// //
// //////////////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////////
//
//
//
Expand Down
63 changes: 63 additions & 0 deletions lib/webdriver-js-extender/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// 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.
*
* 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": "2.53.3",
"source-map-support": "~0.4.0",
"webdriver-manager": "^10.3.0"
"webdriver-manager": "^10.3.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 @@ -76,7 +76,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