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; }); }; 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); + }); +});