Skip to content

Commit

Permalink
chore(types): clean up TypeScript support
Browse files Browse the repository at this point in the history
- fix exampleTypescript to have noGlobals
- change the exampleTypescript tsconfig.json to include @types
- alias promise as wdpromise everywhere
- refactor gulpfile task 'types' to use multiple files from tsc
- add browser method types applied from webdriver

this closes angular#3430, closes angular#3477, and closes angular#3500
  • Loading branch information
cnishina committed Sep 7, 2016
1 parent 00ece71 commit 28a5aa7
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 89 deletions.
1 change: 1 addition & 0 deletions exampleTypescript/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
*.js
node_modules
tmp/
6 changes: 5 additions & 1 deletion exampleTypescript/conf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,9 @@ export let config: Config = {
browserName: 'chrome'
},
specs: [ 'spec.js' ],
seleniumAddress: 'http://localhost:4444/wd/hub'
seleniumAddress: 'http://localhost:4444/wd/hub',

// You could set no globals to true to avoid jQuery '$' and protractor '$'
// collisions on the global namespace.
noGlobals: true
};
3 changes: 2 additions & 1 deletion exampleTypescript/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
"sourceMap": false,
"declaration": false,
"noImplicitAny": false,
"outDir": "tmp"
"outDir": "tmp",
"types": ["node", "jasmine"]
},
"exclude": [
"node_modules",
Expand Down
57 changes: 43 additions & 14 deletions lib/browser.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
// Util from NodeJs
import * as net from 'net';
import {ActionSequence, promise as wdpromise, until, WebDriver, WebElement} from 'selenium-webdriver';
import {
ActionSequence,
Capabilities,
Command as WdCommand,
FileDetector,
Options,
promise as wdpromise,
Session, TargetLocator,
TouchSequence, until,
WebDriver,
WebElement
} from 'selenium-webdriver';

import * as url from 'url';
import * as util from 'util';

Expand Down Expand Up @@ -32,18 +44,29 @@ for (let foo in webdriver) {
exports[foo] = webdriver[foo];
}

// Explicitly define webdriver.WebDriver.
// Explicitly define webdriver.WebDriver
export class Webdriver {
actions: () => ActionSequence = webdriver.WebDriver.actions;
wait:
(condition: wdpromise.Promise<any>|until.Condition<any>|Function,
opt_timeout?: number,
opt_message?:
string) => wdpromise.Promise<any> = webdriver.WebDriver.wait;
sleep: (ms: number) => wdpromise.Promise<any> = webdriver.WebDriver.sleep;
getCurrentUrl:
() => wdpromise.Promise<any> = webdriver.WebDriver.getCurrentUrl;
getTitle: () => wdpromise.Promise<any> = webdriver.WebDriver.getTitle;
actions: () => ActionSequence;
close: () => void;
controlFlow: () => wdpromise.ControlFlow;
executeScript: (script: string|Function, ...var_args: any[]) => wdpromise.Promise<any>;
executeAsyncScript: (script: string|Function, ...var_args: any[]) => wdpromise.Promise<any>;
getCapabilities: () => Capabilities;
getCurrentUrl: () => wdpromise.Promise<string>;
getPageSource: () => wdpromise.Promise<string>;
getSession: () => wdpromise.Promise<Session>;
getTitle: () => wdpromise.Promise<string>;
getWindowHandle: () => wdpromise.Promise<string>;
getAllWindowHandles: () => wdpromise.Promise<string[]>;
manage: () => Options;
quit: () => void;
schedule: (command: WdCommand, description: string) => webdriver.promise.Promise<any>;
setFileDetector: (detector: FileDetector) => void;
sleep: (ms: number) => wdpromise.Promise<void>;
switchTo: () => TargetLocator;
touchActions: () => TouchSequence;
wait: (condition: wdpromise.Promise<any>|until.Condition<any>|Function,
opt_timeout?: number, opt_message?: string) => wdpromise.Promise<any>;
takeScreenshot:
() => wdpromise.Promise<any> = webdriver.WebDriver.takeScreenshot;
}
Expand Down Expand Up @@ -266,7 +289,13 @@ export class ProtractorBrowser extends Webdriver {
// These functions should delegate to the webdriver instance, but should
// 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 methodsToSync = [
'actions', 'close', 'controlFlow', 'executeScript', 'executeAsyncScript',
'getCapabilities', 'getCurrentUrl', 'getPageSource', 'getSession',
'getTitle', 'getWindowHandle', 'getAllWindowHandles', 'manage', 'quit',
'schedule', 'setFileDetector', 'sleep', 'switchTo', 'touchActions',
'touchSequence', 'wait'
];


// Mix all other driver functionality into Protractor.
Expand Down Expand Up @@ -572,7 +601,7 @@ export class ProtractorBrowser extends Webdriver {
* @returns {!webdriver.promise.Promise} A promise that will resolve to whether
* the element is present on the page.
*/
isElementPresent(locatorOrElement: webdriver.Locator|
isElementPresent(locatorOrElement: ProtractorBy|
webdriver.WebElement): webdriver.promise.Promise<any> {
let element = ((locatorOrElement as any).isPresent) ?
locatorOrElement :
Expand Down
84 changes: 42 additions & 42 deletions lib/element.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {By, error, promise, WebDriver, WebElement, WebElementPromise} from 'selenium-webdriver';
import {By, error, ILocation, ISize, promise as wdpromise, WebDriver, WebElement, WebElementPromise} from 'selenium-webdriver';

import {ElementHelper} from './browser';
import {ProtractorBrowser} from './browser';
Expand All @@ -20,25 +20,25 @@ let WEB_ELEMENT_FUNCTIONS = [
// Explicitly define webdriver.WebElement.
export class WebdriverWebElement {
getDriver: () => WebDriver;
getId: () => promise.Promise<any>;
getRawId: () => promise.Promise<string>;
serialize: () => promise.Promise<any>;
findElement: (subLocator: Locator) => promise.Promise<any>;
click: () => promise.Promise<void>;
sendKeys:
(...args: (string|promise.Promise<string>)[]) => promise.Promise<void>;
getTagName: () => promise.Promise<string>;
getCssValue: (cssStyleProperty: string) => promise.Promise<string>;
getAttribute: (attributeName: string) => promise.Promise<string>;
getText: () => promise.Promise<string>;
getSize: () => promise.Promise<{width: number, height: number}>;
getLocation: () => promise.Promise<{x: number, y: number}>;
isEnabled: () => promise.Promise<boolean>;
isSelected: () => promise.Promise<boolean>;
submit: () => promise.Promise<void>;
clear: () => promise.Promise<void>;
isDisplayed: () => promise.Promise<boolean>;
takeScreenshot: (opt_scroll?: boolean) => promise.Promise<string>;
getId: () => wdpromise.Promise<any>;
getRawId: () => wdpromise.Promise<string>;
serialize: () => wdpromise.Promise<any>;
findElement: (subLocator: Locator) => wdpromise.Promise<any>;
click: () => wdpromise.Promise<void>;
sendKeys: (...args: (string|
wdpromise.Promise<string>)[]) => wdpromise.Promise<void>;
getTagName: () => wdpromise.Promise<string>;
getCssValue: (cssStyleProperty: string) => wdpromise.Promise<string>;
getAttribute: (attributeName: string) => wdpromise.Promise<string>;
getText: () => wdpromise.Promise<string>;
getSize: () => wdpromise.Promise<ISize>;
getLocation: () => wdpromise.Promise<ILocation>;
isEnabled: () => wdpromise.Promise<boolean>;
isSelected: () => wdpromise.Promise<boolean>;
submit: () => wdpromise.Promise<void>;
clear: () => wdpromise.Promise<void>;
isDisplayed: () => wdpromise.Promise<boolean>;
takeScreenshot: (opt_scroll?: boolean) => wdpromise.Promise<string>;
}

/**
Expand Down Expand Up @@ -97,9 +97,9 @@ export class WebdriverWebElement {
export class ElementArrayFinder extends WebdriverWebElement {
constructor(
public browser_: ProtractorBrowser,
public getWebElements: () => promise.Promise<WebElement[]> = null,
public locator_?: any,
public actionResults_: promise.Promise<any> = null) {
public getWebElements: () => wdpromise.Promise<WebElement[]> = null,
public locator_: any,
public actionResults_: wdpromise.Promise<any> = null) {
super();

// TODO(juliemr): might it be easier to combine this with our docs and just
Expand Down Expand Up @@ -163,11 +163,11 @@ export class ElementArrayFinder extends WebdriverWebElement {
*/
all(locator: Locator): ElementArrayFinder {
let ptor = this.browser_;
let getWebElements = (): promise.Promise<WebElement[]> => {
let getWebElements = (): wdpromise.Promise<WebElement[]> => {
if (this.getWebElements === null) {
// This is the first time we are looking for an element
return ptor.waitForAngular('Locator: ' + locator)
.then((): promise.Promise<webdriver.WebElement[]> => {
.then((): wdpromise.Promise<webdriver.WebElement[]> => {
if (locator.findElementsOverride) {
return locator.findElementsOverride(
ptor.driver, null, ptor.rootEl);
Expand All @@ -192,7 +192,7 @@ export class ElementArrayFinder extends WebdriverWebElement {
// Resolve the list of Promise<List<child_web_elements>> and merge
// into
// a single list
return promise.all(childrenPromiseList)
return wdpromise.all(childrenPromiseList)
.then((resolved: webdriver.WebElement[]) => {
return resolved.reduce(
(childrenList: webdriver.WebElement[],
Expand Down Expand Up @@ -239,7 +239,7 @@ export class ElementArrayFinder extends WebdriverWebElement {
* of element that satisfy the filter function.
*/
filter(filterFn: Function): ElementArrayFinder {
let getWebElements = (): promise.Promise<WebElement[]> => {
let getWebElements = (): wdpromise.Promise<WebElement[]> => {
return this.getWebElements().then((parentWebElements: WebElement[]) => {
let list = parentWebElements.map(
(parentWebElement: WebElement, index: number) => {
Expand Down Expand Up @@ -385,7 +385,7 @@ export class ElementArrayFinder extends WebdriverWebElement {
* @returns {!webdriver.promise.Promise} A promise which resolves to the
* number of elements matching the locator.
*/
count(): promise.Promise<number> {
count(): wdpromise.Promise<number> {
return this.getWebElements().then(
(arr: WebElement[]) => { return arr.length; },
(err: IError) => {
Expand Down Expand Up @@ -458,7 +458,7 @@ export class ElementArrayFinder extends WebdriverWebElement {
* @returns {Array.<ElementFinder>} Return a promise, which resolves to a list
* of ElementFinders specified by the locator.
*/
asElementFinders_(): promise.Promise<any> {
asElementFinders_(): wdpromise.Promise<any> {
return this.getWebElements().then((arr: WebElement[]) => {
return arr.map((webElem: WebElement) => {
return ElementFinder.fromWebElement_(
Expand Down Expand Up @@ -491,7 +491,7 @@ export class ElementArrayFinder extends WebdriverWebElement {
* @returns {!webdriver.promise.Promise} A promise which will resolve to
* an array of ElementFinders represented by the ElementArrayFinder.
*/
then(fn: Function, errorFn: Function): promise.Promise<any> {
then(fn: Function, errorFn: Function): wdpromise.Promise<any> {
if (this.actionResults_) {
return this.actionResults_.then(fn, errorFn);
} else {
Expand Down Expand Up @@ -526,7 +526,7 @@ export class ElementArrayFinder extends WebdriverWebElement {
* resolve to null.
*/
each(fn: (elementFinder: ElementFinder, index: number) => any):
promise.Promise<any> {
wdpromise.Promise<any> {
return this.map(fn).then((): any => { return null; });
}

Expand Down Expand Up @@ -563,14 +563,14 @@ export class ElementArrayFinder extends WebdriverWebElement {
* of values returned by the map function.
*/
map(mapFn: (elementFinder: ElementFinder, index: number) => any):
promise.Promise<any> {
wdpromise.Promise<any> {
return this.asElementFinders_().then((arr: ElementFinder[]) => {
let list = arr.map((elementFinder: ElementFinder, index: number) => {
let mapResult = mapFn(elementFinder, index);
// All nested arrays and objects will also be fully resolved.
return promise.fullyResolved(mapResult);
return wdpromise.fullyResolved(mapResult);
});
return promise.all(list);
return wdpromise.all(list);
});
};

Expand Down Expand Up @@ -606,8 +606,8 @@ export class ElementArrayFinder extends WebdriverWebElement {
* @returns {!webdriver.promise.Promise} A promise that resolves to the final
* value of the accumulator.
*/
reduce(reduceFn: Function, initialValue: any): promise.Promise<any> {
let valuePromise = promise.fulfilled(initialValue);
reduce(reduceFn: Function, initialValue: any): wdpromise.Promise<any> {
let valuePromise = wdpromise.fulfilled(initialValue);
return this.asElementFinders_().then((arr: ElementFinder[]) => {
return arr.reduce(
(valuePromise: any, elementFinder: ElementFinder, index: number) => {
Expand Down Expand Up @@ -714,7 +714,7 @@ export class ElementArrayFinder extends WebdriverWebElement {
export class ElementFinder extends WebdriverWebElement {
parentElementArrayFinder: ElementArrayFinder;
elementArrayFinder_: ElementArrayFinder;
then: (fn: Function, errorFn: Function) => promise.Promise<any> = null;
then: (fn: Function, errorFn: Function) => wdpromise.Promise<any> = null;

constructor(
public browser_: ProtractorBrowser,
Expand Down Expand Up @@ -752,7 +752,7 @@ export class ElementFinder extends WebdriverWebElement {
// This filter verifies that there is only 1 element returned by the
// elementArrayFinder. It will warn if there are more than 1 element and
// throw an error if there are no elements.
let getWebElements = (): promise.Promise<WebElement[]> => {
let getWebElements = (): wdpromise.Promise<WebElement[]> => {
return elementArrayFinder.getWebElements().then(
(webElements: WebElement[]) => {
if (webElements.length === 0) {
Expand Down Expand Up @@ -790,7 +790,7 @@ export class ElementFinder extends WebdriverWebElement {
static fromWebElement_(
browser: ProtractorBrowser, webElem: WebElement,
locator: Locator): ElementFinder {
let getWebElements = () => { return promise.fulfilled([webElem]); };
let getWebElements = () => { return wdpromise.fulfilled([webElem]); };
return new ElementArrayFinder(browser, getWebElements, locator)
.toElementFinder_();
}
Expand Down Expand Up @@ -965,7 +965,7 @@ export class ElementFinder extends WebdriverWebElement {
* @returns {webdriver.promise.Promise<boolean>} which resolves to whether
* the element is present on the page.
*/
isPresent(): promise.Promise<boolean> {
isPresent(): wdpromise.Promise<boolean> {
return this.parentElementArrayFinder.getWebElements().then(
(arr: any[]) => {
if (arr.length === 0) {
Expand Down Expand Up @@ -1005,7 +1005,7 @@ export class ElementFinder extends WebdriverWebElement {
* @returns {webdriver.promise.Promise<boolean>} which resolves to whether
* the subelement is present on the page.
*/
isElementPresent(subLocator: Locator): promise.Promise<boolean> {
isElementPresent(subLocator: Locator): wdpromise.Promise<boolean> {
if (!subLocator) {
throw new Error(
'SubLocator is not supplied as a parameter to ' +
Expand Down Expand Up @@ -1051,7 +1051,7 @@ export class ElementFinder extends WebdriverWebElement {
* @returns {!webdriver.promise.Promise.<boolean>} A promise that will be
* resolved to whether the two WebElements are equal.
*/
equals(element: ElementFinder|WebElement): promise.Promise<any> {
equals(element: ElementFinder|WebElement): wdpromise.Promise<any> {
return WebElement.equals(
this.getWebElement(), (element as any).getWebElement ?
(element as ElementFinder).getWebElement() :
Expand Down
17 changes: 1 addition & 16 deletions lib/globals.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ declare namespace NodeJS {
Command: any;
CommandName: any;
// Helper function added by the debugger in protractor.ps
list: (locator: webdriver.Locator) => string[];
list: (locator: any) => string[];
[key: string]: any;
}
}
Expand All @@ -38,24 +38,9 @@ declare interface IError extends Error {
declare interface String { startsWith: Function; }

declare namespace webdriver {
namespace promise {
interface Promise<T> {
controlFlow: Function;
}
}

namespace util {
interface Condition {}
}

class ErrorCode {
code: number;
}

interface Locator {
toString(): string;
isPresent?: Function;
}
}

declare interface HttpProxyAgent { constructor(opts: Object): HttpProxyAgent; }
Loading

0 comments on commit 28a5aa7

Please sign in to comment.