From 1f52aa4530c1229909b63353cfd689db01b2de4d Mon Sep 17 00:00:00 2001 From: Harold Hunt Date: Sun, 3 Oct 2021 01:48:46 -0400 Subject: [PATCH] Add test cases for multiple mapper errors with stop on error (#49) Co-authored-by: Sindre Sorhus --- index.d.ts | 6 +++++- readme.md | 6 +++++- test.js | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/index.d.ts b/index.d.ts index a5423ff..8083ba3 100644 --- a/index.d.ts +++ b/index.d.ts @@ -9,7 +9,11 @@ export interface Options { readonly concurrency?: number; /** - When set to `false`, instead of stopping when a promise rejects, it will wait for all the promises to settle and then reject with an [aggregated error](https://github.com/sindresorhus/aggregate-error) containing all the errors from the rejected promises. + When `true`, the first mapper rejection will be rejected back to the consumer. + + When `false`, instead of stopping when a promise rejects, it will wait for all the promises to settle and then reject with an [aggregated error](https://github.com/sindresorhus/aggregate-error) containing all the errors from the rejected promises. + + Caveat: When `true`, any already-started async mappers will continue to run until they resolve or reject. In the case of infinite concurrency with sync iterables, *all* mappers are invoked on startup and will continue after the first rejection. [Issue #51](https://github.com/sindresorhus/p-map/issues/51) can be implemented for abort control. @default true */ diff --git a/readme.md b/readme.md index 7c8ba3a..a59bfa0 100644 --- a/readme.md +++ b/readme.md @@ -72,7 +72,11 @@ Number of concurrently pending promises returned by `mapper`. Type: `boolean`\ Default: `true` -When set to `false`, instead of stopping when a promise rejects, it will wait for all the promises to settle and then reject with an [aggregated error](https://github.com/sindresorhus/aggregate-error) containing all the errors from the rejected promises. +When `true`, the first mapper rejection will be rejected back to the consumer. + +When `false`, instead of stopping when a promise rejects, it will wait for all the promises to settle and then reject with an [aggregated error](https://github.com/sindresorhus/aggregate-error) containing all the errors from the rejected promises. + +Caveat: When `true`, any already-started async mappers will continue to run until they resolve or reject. In the case of infinite concurrency with sync iterables, *all* mappers are invoked on startup and will continue after the first rejection. [Issue #51](https://github.com/sindresorhus/p-map/issues/51) can be implemented for abort control. ### pMapSkip diff --git a/test.js b/test.js index 2120258..4c13d78 100644 --- a/test.js +++ b/test.js @@ -378,3 +378,35 @@ test('incorrect input type', async t => { await t.throwsAsync(task, {message: 'Expected `input` to be either an `Iterable` or `AsyncIterable`, got (number)'}); t.false(mapperCalled); }); + +test('no unhandled rejected promises from mapper throws - infinite concurrency', async t => { + const input = [1, 2, 3]; + const mappedValues = []; + await t.throwsAsync( + pMap(input, async value => { + mappedValues.push(value); + await delay(100); + throw new Error(`Oops! ${value}`); + }), + {message: 'Oops! 1'} + ); + // Note: All 3 mappers get invoked, all 3 throw, even with `{stopOnError: true}` this + // should raise an AggregateError with all 3 exceptions instead of throwing 1 + // exception and hiding the other 2. + t.deepEqual(mappedValues, [1, 2, 3]); +}); + +test('no unhandled rejected promises from mapper throws - concurrency 1', async t => { + const input = [1, 2, 3]; + const mappedValues = []; + await t.throwsAsync( + pMap(input, async value => { + mappedValues.push(value); + await delay(100); + throw new Error(`Oops! ${value}`); + }, + {concurrency: 1}), + {message: 'Oops! 1'} + ); + t.deepEqual(mappedValues, [1]); +});