diff --git a/packages/vow/src/when.js b/packages/vow/src/when.js index d346d7e59b0..0bd2aa8e557 100644 --- a/packages/vow/src/when.js +++ b/packages/vow/src/when.js @@ -17,14 +17,10 @@ export const makeWhen = ( * @see {@link ../../README.md} * * @template T - * @template [TResult1=EUnwrap] - * @template [TResult2=never] * @param {T} specimenP value to unwrap - * @param {(value: EUnwrap) => TResult1 | PromiseLike} [onFulfilled] - * @param {(reason: any) => TResult2 | PromiseLike} [onRejected] - * @returns {Promise} + * @returns {Promise>} */ - const when = async (specimenP, onFulfilled, onRejected) => { + const unwrap = async specimenP => { // Ensure we don't run until a subsequent turn. await null; @@ -63,10 +59,30 @@ export const makeWhen = ( } const unwrapped = /** @type {EUnwrap} */ (result); + return unwrapped; + }; + + /** + * Shorten `specimenP` until we achieve a final result. + * + * Does not survive upgrade (even if specimenP is a durable Vow). + * + * @see {@link ../../README.md} + * + * @template T + * @template [TResult1=EUnwrap] + * @template [TResult2=never] + * @param {T} specimenP value to unwrap + * @param {(value: EUnwrap) => TResult1 | PromiseLike} [onFulfilled] + * @param {(reason: any) => TResult2 | PromiseLike} [onRejected] + * @returns {Promise} + */ + const when = (specimenP, onFulfilled, onRejected) => { + const unwrapped = unwrap(specimenP); // We've extracted the final result. if (onFulfilled == null && onRejected == null) { - return /** @type {TResult1} */ (unwrapped); + return /** @type {Promise} */ (unwrapped); } return basicE.resolve(unwrapped).then(onFulfilled, onRejected); }; diff --git a/packages/vow/test/disconnect.test.js b/packages/vow/test/disconnect.test.js index 5d44b740558..35713076214 100644 --- a/packages/vow/test/disconnect.test.js +++ b/packages/vow/test/disconnect.test.js @@ -54,7 +54,12 @@ test('retry on disconnection', async t => { [2, 'disco', 'disco', 'sad'], ]; - for await (const pattern of ['when', 'watch']) { + for await (const pattern of [ + 'when', + 'when-with-handlers', + 'watch', + 'watch-with-handler', + ]) { t.log('testing', pattern); for await (const [final, ...plan] of PLANS) { t.log(`testing (plan=${plan}, ${pattern})`); @@ -66,7 +71,7 @@ test('retry on disconnection', async t => { let resultP; switch (pattern) { - case 'watch': { + case 'watch-with-handler': { const resultW = watch(vow, { onFulfilled(value) { t.is(plan[final], 'happy'); @@ -83,10 +88,24 @@ test('retry on disconnection', async t => { resultP = when(resultW); break; } + case 'watch': { + const resultW = watch(vow); + t.is('then' in resultW, false, 'watch resultW.then is undefined'); + resultP = when(resultW).catch(e => ['rejected', e]); + break; + } case 'when': { resultP = when(vow).catch(e => ['rejected', e]); break; } + case 'when-with-handlers': { + resultP = when( + vow, + v => v, + e => ['rejected', e], + ); + break; + } default: { t.fail(`unknown pattern ${pattern}`); }