From b67a868229b3dca2119a97ea0cc24d9ee9107498 Mon Sep 17 00:00:00 2001 From: Wilfred van der Deijl Date: Tue, 26 Sep 2017 15:03:19 +0200 Subject: [PATCH 1/2] fix(element): prevent concurrent map functions prevents running multiple concurrent webdriver commands when selenium promise manager is disabled --- lib/element.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/element.ts b/lib/element.ts index ee6d3d5af..0bac0a4ba 100644 --- a/lib/element.ts +++ b/lib/element.ts @@ -652,13 +652,17 @@ export class ElementArrayFinder extends WebdriverWebElement { */ map(mapFn: (elementFinder?: ElementFinder, index?: number) => T | any): wdpromise.Promise { - 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 wdpromise.fullyResolved(mapResult) as wdpromise.Promise; + const finders = this.asElementFinders_(); + // execute mapFn one-at-a-time to prevent concurrent webdriver requests + return finders.then(arr => { + let promise = finders.then(() => []); + arr.forEach((elementFinder, index) => { + promise = promise.then(result => { + const mapResult = wdpromise.fullyResolved(mapFn(elementFinder, index)); + return mapResult.then(mr => result.concat([mr])); + }); }); - return wdpromise.all(list); + return promise; }); }; From 513604fe501167c6c7b89a3dba35a26f74f67664 Mon Sep 17 00:00:00 2001 From: Wilfred van der Deijl Date: Wed, 4 Oct 2017 15:04:10 +0200 Subject: [PATCH 2/2] tests for #4507 --- spec/ts/basic/element_spec.ts | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/spec/ts/basic/element_spec.ts b/spec/ts/basic/element_spec.ts index 18ca6a7da..d813c49d2 100644 --- a/spec/ts/basic/element_spec.ts +++ b/spec/ts/basic/element_spec.ts @@ -184,3 +184,28 @@ describe('ElementFinder', function() { await expect(usernameInput.equals(name)).toEqual(false); }); }); + +describe('ElementArrayFinder', function() { + it('should be able to invoke #map on many elements', async () => { + // running map callbacks concurrently would crash webdriver as it can't handle + // concurrent requests (at least no with Crome on MacOS) + await browser.get('index.html#/form'); + await element.all(by.css('*')).map(elem => elem.getText().then(_ => {})); + // no real expectation, the real target is that we get here without exceptions + }); + + it('should invoke ElementArrayFinder.map callbacks sequentially', async () => { + await browser.get('index.html#/form'); + let running = 0; + let highwater = 0; + await element.all(by.css('*')).map(elem => Promise.resolve() + .then(() => { + running++; + highwater = Math.max(running, highwater); + return new Promise(resolve => setTimeout(resolve, 1)); + }) + .then(() => {running--;}) + ); + expect(highwater).toEqual(1); + }); +});