From 768fd393d1084a8da0ec6eeaa57508bf17519a3f Mon Sep 17 00:00:00 2001 From: Craig Date: Sun, 30 Jul 2017 22:17:21 -0700 Subject: [PATCH] fix(local): allow local driver provider to use gecko driver from config (#4412) - Add gecko driver as configuration option to be used in the local driver provider. - Nit fixes to use `string[]` over `Array` in the configParser.ts. - Add functionality to `addDefaultBinaryLocs_` to use the `geckoDriver` value set in the config or to check locally in the `webdriver-manager/selenium` folder. - Fix transpile errors in locator. Missing toString in ProtractorLocator interface. - Fix transpile errors in element. Cast wdpromise.Promise<{}> to wdpromise.Promise. - xit spec/basic/action_spec.js based on [selenium-webdriver issue #3693](https://github.com/SeleniumHQ/selenium/issues/3693). Added a // TODO comment to remove xit when selenium-webdriver resolves issue. closes #4408 and closes #4411. --- lib/config.ts | 14 ++++++++++---- lib/configParser.ts | 20 ++++++++++---------- lib/driverProviders/local.ts | 31 +++++++++++++++++++++++++++++++ lib/element.ts | 2 +- lib/locators.ts | 1 + spec/basic/actions_spec.js | 4 +++- 6 files changed, 56 insertions(+), 16 deletions(-) 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/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; diff --git a/spec/basic/actions_spec.js b/spec/basic/actions_spec.js index 7bddb0fc7..b203ad300 100644 --- a/spec/basic/actions_spec.js +++ b/spec/basic/actions_spec.js @@ -3,7 +3,9 @@ describe('using an ActionSequence', function() { browser.get('index.html#/form'); }); - it('should drag and drop', function() { + // TODO(cnishina): update when mouseMoveTo works in the next release of selenium-webdriver. + // Refer to selenium-webdriver issue 3693. https://github.com/SeleniumHQ/selenium/issues/3693 + xit('should drag and drop', function() { var sliderBar = element(by.name('points')); expect(sliderBar.getAttribute('value')).toEqual('1');