From af84deebe33823c13daab737880a20e4a63d18c0 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 | 2 ++ readme.md | 2 ++ test.js | 31 +++++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+) diff --git a/index.d.ts b/index.d.ts index a5423ff..e87e6cc 100644 --- a/index.d.ts +++ b/index.d.ts @@ -9,6 +9,8 @@ export interface Options { readonly concurrency?: number; /** + When set to `true`, the first mapper rejection will be rejected back to the consumer. Caveat: 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](issues/51) can be implemented for abort control. + 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. @default true diff --git a/readme.md b/readme.md index 7c8ba3a..d066fc7 100644 --- a/readme.md +++ b/readme.md @@ -72,6 +72,8 @@ Number of concurrently pending promises returned by `mapper`. Type: `boolean`\ Default: `true` +When set to `true`, the first mapper rejection will be rejected back to the consumer. Caveat: 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](issues/51) can be implemented for abort control. + 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. ### pMapSkip diff --git a/test.js b/test.js index 2120258..7d1ce0c 100644 --- a/test.js +++ b/test.js @@ -378,3 +378,34 @@ 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]); +});