diff --git a/lib/browser.ts b/lib/browser.ts index 85d620451..239669335 100644 --- a/lib/browser.ts +++ b/lib/browser.ts @@ -89,8 +89,8 @@ export interface ElementHelper extends Function { */ function buildElementHelper(browser: ProtractorBrowser): ElementHelper { let element = ((locator: Locator) => { - return new ElementArrayFinder(browser).all(locator).toElementFinder_(); - }) as ElementHelper; + return new ElementArrayFinder(browser).all(locator).toElementFinder_(); + }) as ElementHelper; element.all = (locator: Locator) => { return new ElementArrayFinder(browser).all(locator); @@ -1047,8 +1047,8 @@ export class ProtractorBrowser extends AbstractExtendedWebDriver { clientSideScripts.setLocation, 'Protractor.setLocation()', rootEl, url) .then((browserErr: Error) => { if (browserErr) { - throw 'Error while navigating to \'' + url + - '\' : ' + JSON.stringify(browserErr); + throw 'Error while navigating to \'' + url + '\' : ' + + JSON.stringify(browserErr); } })); } diff --git a/lib/config.ts b/lib/config.ts index d7e51eb6d..eb0be09b9 100644 --- a/lib/config.ts +++ b/lib/config.ts @@ -66,16 +66,22 @@ export interface Config { jvmArgs?: string[]; }; /** - * ChromeDriver location is used to help find the chromedriver binary. - * This will be passed to the Selenium jar as the system property - * webdriver.chrome.driver. If null, Selenium will attempt to find - * ChromeDriver using PATH. + * ChromeDriver location is used to help find the chromedriver binary. This will be passed to the + * Selenium jar as the system property webdriver.chrome.driver. If the value is not set when + * launching locally, it will use the default values downloaded from webdriver-manager. * * example: * chromeDriver: './node_modules/webdriver-manager/selenium/chromedriver_2.20' */ chromeDriver?: string; + /** + * geckoDriver location is used to help find the gecko binary. This will be passed to the Selenium + * jar as the system property webdriver.gecko.driver. If the value is not set when launching + * locally, it will use the default values downloaded from webdriver-manager. + */ + geckoDriver?: string; + // ---- 2. To connect to a Selenium Server which is already running ---------- /** diff --git a/lib/configParser.ts b/lib/configParser.ts index 51715ba30..d85800c44 100644 --- a/lib/configParser.ts +++ b/lib/configParser.ts @@ -55,9 +55,8 @@ export class ConfigParser { * @return {Array} The resolved file paths. */ public static resolveFilePatterns( - patterns: Array|string, opt_omitWarnings?: boolean, - opt_relativeTo?: string): Array { - let resolvedFiles: Array = []; + patterns: string[]|string, opt_omitWarnings?: boolean, opt_relativeTo?: string): string[] { + let resolvedFiles: string[] = []; let cwd = opt_relativeTo || process.cwd(); patterns = (typeof patterns === 'string') ? [patterns] : patterns; @@ -82,8 +81,8 @@ export class ConfigParser { * * @return {Array} An array of globs locating the spec files */ - static getSpecs(config: Config): Array { - let specs: Array = []; + static getSpecs(config: Config): string[] { + let specs: string[] = []; if (config.suite) { config.suite.split(',').forEach((suite) => { let suiteList = config.suites ? config.suites[suite] : null; @@ -115,8 +114,9 @@ export class ConfigParser { private addConfig_(additionalConfig: any, relativeTo: string): void { // All filepaths should be kept relative to the current config location. // This will not affect absolute paths. - ['seleniumServerJar', 'chromeDriver', 'onPrepare', 'firefoxPath', 'frameworkPath'].forEach( - (name) => { + ['seleniumServerJar', 'chromeDriver', 'firefoxPath', 'frameworkPath', 'geckoDriver', + 'onPrepare'] + .forEach((name: string) => { if (additionalConfig[name] && typeof additionalConfig[name] === 'string') { additionalConfig[name] = path.resolve(relativeTo, additionalConfig[name]); } @@ -206,10 +206,10 @@ let makeArray = function(item: any): any { * Adds to an array all the elements in another array without adding any * duplicates * - * @param {Array} dest The array to add to - * @param {Array} src The array to copy from + * @param {string[]} dest The array to add to + * @param {string[]} src The array to copy from */ -let union = function(dest: Array, src: Array): void { +let union = function(dest: string[], src: string[]): void { let elems: any = {}; for (let key in dest) { elems[dest[key]] = true; diff --git a/lib/driverProviders/local.ts b/lib/driverProviders/local.ts index 9c9396ea9..aa2edf2b9 100644 --- a/lib/driverProviders/local.ts +++ b/lib/driverProviders/local.ts @@ -86,6 +86,37 @@ export class Local extends DriverProvider { } } } + + if (this.config_.capabilities.browserName === 'firefox') { + if (!this.config_.geckoDriver) { + logger.debug( + 'Attempting to find the gecko driver binary in the default ' + + 'location used by webdriver-manager'); + + try { + let updateJson = path.resolve(SeleniumConfig.getSeleniumDir(), 'update-config.json'); + let updateConfig = JSON.parse(fs.readFileSync(updateJson).toString()); + this.config_.geckoDriver = updateConfig.gecko.last; + } catch (err) { + throw new BrowserError( + logger, + 'No update-config.json found. ' + + 'Run \'webdriver-manager update\' to download binaries.'); + } + } + + // Check if file exists, if not try .exe or fail accordingly + if (!fs.existsSync(this.config_.geckoDriver)) { + if (fs.existsSync(this.config_.geckoDriver + '.exe')) { + this.config_.geckoDriver += '.exe'; + } else { + throw new BrowserError( + logger, + 'Could not find gecko driver at ' + this.config_.geckoDriver + + '. Run \'webdriver-manager update\' to download binaries.'); + } + } + } } /** diff --git a/lib/driverProviders/sauce.ts b/lib/driverProviders/sauce.ts index e70984545..208d6e9c5 100644 --- a/lib/driverProviders/sauce.ts +++ b/lib/driverProviders/sauce.ts @@ -65,9 +65,9 @@ export class Sauce extends DriverProvider { this.config_.capabilities['build'] = this.config_.sauceBuild; let protocol = this.config_.sauceSeleniumUseHttp ? 'http://' : 'https://'; let auth = protocol + this.config_.sauceUser + ':' + this.config_.sauceKey + '@'; - this.config_.seleniumAddress = auth + - (this.config_.sauceSeleniumAddress ? this.config_.sauceSeleniumAddress : - 'ondemand.saucelabs.com:443/wd/hub'); + this.config_.seleniumAddress = + auth + (this.config_.sauceSeleniumAddress ? this.config_.sauceSeleniumAddress : + 'ondemand.saucelabs.com:443/wd/hub'); // Append filename to capabilities.name so that it's easier to identify // tests. diff --git a/lib/element.ts b/lib/element.ts index e987eca38..ee6d3d5af 100644 --- a/lib/element.ts +++ b/lib/element.ts @@ -656,7 +656,7 @@ export class ElementArrayFinder extends WebdriverWebElement { let list = arr.map((elementFinder?: ElementFinder, index?: number) => { let mapResult = mapFn(elementFinder, index); // All nested arrays and objects will also be fully resolved. - return wdpromise.fullyResolved(mapResult); + return wdpromise.fullyResolved(mapResult) as wdpromise.Promise; }); return wdpromise.all(list); }); diff --git a/lib/locators.ts b/lib/locators.ts index 5cf944a30..ae1f538d2 100644 --- a/lib/locators.ts +++ b/lib/locators.ts @@ -25,6 +25,7 @@ export interface ProtractorLocator { rootSelector: string) => wdpromise.Promise; row?: (index: number) => Locator; column?: (index: string) => Locator; + toString?: () => string; } export type Locator = ProtractorLocator | WebDriverLocator;