diff --git a/gulpfile.js b/gulpfile.js index 176196569..722ed9077 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -5,6 +5,9 @@ var clangFormat = require('clang-format'); var gulpFormat = require('gulp-clang-format'); var runSequence = require('run-sequence'); var spawn = require('child_process').spawn; +var fs = require('fs'); +var path = require('path'); +var glob = require('glob'); var runSpawn = function(done, task, opt_arg) { opt_arg = typeof opt_arg !== 'undefined' ? opt_arg : []; @@ -56,12 +59,53 @@ gulp.task('tsc', function(done) { }); gulp.task('prepublish', function(done) { - runSequence(['typings', 'jshint', 'clang'],'tsc', 'built:copy', done); + runSequence(['typings', 'jshint', 'clang'], 'tsc', 'types', 'built:copy', done); }); gulp.task('pretest', function(done) { runSequence( - ['webdriver:update', 'typings', 'jshint', 'clang'], 'tsc', 'built:copy', done); + ['webdriver:update', 'typings', 'jshint', 'clang'], 'tsc', 'types', + 'built:copy', done); }); gulp.task('default',['prepublish']); + +gulp.task('types', function(done) { + var folder = 'built'; + var files = ['ptor', 'browser', 'locators']; + var outputFile = path.resolve(folder, 'index.d.ts'); + var contents = ''; + files.forEach(file => { + contents += parseTypingsFile(folder, file); + }); + + // add module declaration + contents += 'declare module "protractor" {\n'; + contents += ' export = protractor\n'; + contents += '}\n'; + + // remove files with d.ts + glob.sync(folder + '/**/*.d.ts').forEach(file => { + fs.unlinkSync(path.resolve(file)); + }); + + // write contents to 'built/index.d.ts' + fs.writeFileSync(outputFile, contents); + done(); +}); + +var parseTypingsFile = function(folder, file) { + var fileContents = fs.readFileSync(path.resolve(folder, file + '.d.ts')).toString(); + var lines = fileContents.split('\n'); + var contents = ''; + for (var linePos in lines) { + var line = lines[linePos]; + if (!line.startsWith('import')) { + if (line.indexOf('export') !== -1) { + line = line.replace('export', '').trim(); + } + contents += line + '\n'; + } + } + return contents; +} diff --git a/lib/browser.ts b/lib/browser.ts index c51bf56ab..0b0e12662 100644 --- a/lib/browser.ts +++ b/lib/browser.ts @@ -5,7 +5,7 @@ import * as util from 'util'; import {ElementArrayFinder, ElementFinder, build$, build$$} from './element'; import * as EC from './expectedConditions'; -import {ProtractorBy} from './locators'; +import {Locator, ProtractorBy} from './locators'; import {Logger} from './logger2'; import {Plugins} from './plugins'; import {protractor} from './ptor'; @@ -50,8 +50,8 @@ function mixin(to: any, from: any, fnName: string, setupFn?: Function) { }; export interface ElementHelper extends Function { - (locator: webdriver.Locator): ElementFinder; - all?: (locator: webdriver.Locator) => ElementArrayFinder; + (locator: Locator): ElementFinder; + all?: (locator: Locator) => ElementArrayFinder; } /** @@ -62,14 +62,14 @@ export interface ElementHelper extends Function { * @return {function(webdriver.Locator): ElementFinder} */ function buildElementHelper(browser: Browser): ElementHelper { - let element: ElementHelper = function(locator: webdriver.Locator) { + let element: ElementHelper = (locator: Locator) => { return new ElementArrayFinder(browser).all(locator).toElementFinder_(); }; element.all = - function(locator: webdriver.Locator) { - return new ElementArrayFinder(browser).all(locator); - } + (locator: Locator) => { + return new ElementArrayFinder(browser).all(locator); + } return element; }; @@ -294,7 +294,8 @@ export class Browser { * @param {boolean} opt_copyMockModules Whether to apply same mock modules on creation * @return {Protractor} a protractor instance. */ - forkNewDriverInstance: (opt_useSameUrl?: boolean, opt_copyMockModules?: boolean) => Browser; + forkNewDriverInstance: + (opt_useSameUrl?: boolean, opt_copyMockModules?: boolean) => Browser; /** * Restart the browser instance. @@ -499,7 +500,7 @@ export class Browser { * @see webdriver.WebDriver.findElement * @return {!webdriver.WebElement} */ - findElement(locator: webdriver.Locator): webdriver.WebElement { + findElement(locator: Locator): webdriver.WebElement { return this.element(locator).getWebElement(); } @@ -509,7 +510,7 @@ export class Browser { * @return {!webdriver.promise.Promise} A promise that will be resolved to an * array of the located {@link webdriver.WebElement}s. */ - findElements(locator: webdriver.Locator): webdriver.Promise { + findElements(locator: Locator): webdriver.Promise { return this.element.all(locator).getWebElements(); } @@ -969,7 +970,7 @@ export class Browser { let flow = webdriver.promise.controlFlow(); let context: Object = {require: require}; - global.list = (locator: webdriver.Locator) => { + global.list = (locator: Locator) => { /* globals browser */ return protractor.browser.findElements(locator).then( (arr: webdriver.WebElement[]) => { diff --git a/lib/element.ts b/lib/element.ts index d4fb24d75..d3da23131 100644 --- a/lib/element.ts +++ b/lib/element.ts @@ -3,6 +3,7 @@ let clientSideScripts = require('./clientsidescripts'); import {Logger} from './logger2'; import {Browser} from './browser'; +import {Locator} from './locators'; let logger = new Logger('element'); @@ -131,7 +132,7 @@ export class ElementArrayFinder { * @param {webdriver.Locator} subLocator * @return {ElementArrayFinder} */ - all(locator: any): ElementArrayFinder { + all(locator: Locator): ElementArrayFinder { let ptor = this.browser_; let getWebElements = () => { if (this.getWebElements === null) { @@ -396,7 +397,8 @@ export class ElementArrayFinder { }) .then(null, (e: Error) => { let noSuchErr = (e as any); - noSuchErr.stack = noSuchErr.stack + (callerError as any).stack; + noSuchErr.stack = + noSuchErr.stack + (callerError as any).stack; throw noSuchErr; }); return new ElementArrayFinder( diff --git a/lib/locators.ts b/lib/locators.ts index 113c0e0ae..e81ed81a4 100644 --- a/lib/locators.ts +++ b/lib/locators.ts @@ -6,17 +6,16 @@ let clientSideScripts: any = require('./clientsidescripts'); * webdriver's By is an enum of locator functions, so we must set it to * a prototype before inheriting from it. */ -export class WebdriverBy {}; +export class WebdriverBy {} WebdriverBy.prototype = webdriver.By; -export interface Locator extends webdriver.Locator { +export interface Locator { findElementsOverride?: (driver: webdriver.WebDriver, using: webdriver.WebElement, rootSelector: string) => webdriver.WebElement; row?: (index: number) => Locator; column?: (index: string) => Locator; } -; /** * The Protractor Locators. These provide ways of finding elements in @@ -26,9 +25,19 @@ export interface Locator extends webdriver.Locator { * @extends {webdriver.By} */ export class ProtractorBy extends WebdriverBy { - // Explicit index signature to fix TS warining. [key: string]: any; + className: (className: string) => Locator = webdriver.By.className; + css: (css: string) => Locator = webdriver.By.css; + id: (id: string) => Locator = webdriver.By.id; + linkText: (linkText: string) => Locator = webdriver.By.linkText; + js: (js: string) => Locator = webdriver.By.js; + name: (name: string) => Locator = webdriver.By.name; + partialLinkText: + (partialText: string) => Locator = webdriver.By.partialLinkText; + tagName: (tagName: string) => Locator = webdriver.By.tagName; + xpath: (xpath: string) => Locator = webdriver.By.xpath; + /** * Add a locator to this instance of ProtractorBy. This locator can then be * used with element(by.locatorName(args)). @@ -378,7 +387,6 @@ export class ProtractorBy extends WebdriverBy { return this.byRepeaterInner(true, repeatDescriptor); } - /** * Find elements by CSS which contain a certain string. *