UNPKG

@debonet/es6pacts

Version:

Releasable/cancellable and Reporting Promises for Javascript ES6

156 lines (143 loc) 4.88 kB
const Pact = require( "../src/es6pacts.js" ); const fpTick = () => new Promise(( fOk ) => setTimeout( fOk, 0 )); const ftPact = ( fpRelease ) => { let fReportT; const pact = new Pact(( fResolve, fReject, fReport ) => { fReportT = fReport; return fpRelease; }); return [ pact, fReportT ]; }; test( "executor receives fReport as the third parameter", () => { let fReportT; new Pact(( fResolve, fReject, fReport ) => { fReportT = fReport; return () => undefined; }); expect( typeof fReportT ).toBe( "function" ); }); test( "observers get the same raw value in attachment order", async () => { const [ pact, fReportT ] = ftPact(() => undefined ); const vtLog = []; const xRaw = { z : 1 }; pact.progress(( x ) => vtLog.push([ "a", x ])); pact.progress(( x ) => vtLog.push([ "b", x ])); fReportT( xRaw ); await fpTick(); expect( vtLog ).toEqual([[ "a", xRaw ], [ "b", xRaw ]]); expect( vtLog[ 0 ][ 1 ]).toBe( xRaw ); expect( vtLog[ 1 ][ 1 ]).toBe( xRaw ); }); test( "release runs the cleanup, settles by dispatch, drops later reports", async () => { let bCleaned = false; const [ pact, fReportT ] = ftPact(() => { bCleaned = true; }); const vxLog = []; pact.progress(( x ) => vxLog.push( x )); fReportT( "before" ); const aSettlement = await pact.release( "early" ); expect( bCleaned ).toBe( true ); expect( aSettlement ).toEqual({ sStatus : "resolved", x : "early" }); await expect( pact ).resolves.toBe( "early" ); fReportT( "after" ); await fpTick(); expect( vxLog ).toEqual([ "before" ]); } ); test( "a refused release leaves the pact pending with reports flowing", async () => { const [ pact, fReportT ] = ftPact( () => Promise.reject( new Error( "busy" )) ); const vxLog = []; pact.progress(( x ) => vxLog.push( x )); await expect( pact.release( "stop" )).rejects.toThrow( "busy" ); fReportT( "still working" ); const xState = await Promise.race([ pact, fpTick().then(() => "pending" ) ]); expect( xState ).toBe( "pending" ); expect( vxLog ).toEqual([ "still working" ]); } ); test( "resolve verb flows an early value down a reporting chain", async () => { const [ pact, fReportT ] = ftPact(() => undefined ); const vxLog = []; const pactDone = pact .progress(( x ) => vxLog.push( x )) .then(( s ) => s + "!" ); fReportT( "working" ); await pact.resolve( "early" ); await expect( pactDone ).resolves.toBe( "early!" ); expect( vxLog ).toEqual([ "working" ]); }); test( "reject verb rejects down a reporting chain", async () => { const [ pact ] = ftPact(() => undefined ); const vxLog = []; const pactCaught = pact .progress(( x ) => vxLog.push( x )) .catch(( xErr ) => "caught:" + xErr.message ); await pact.reject( new Error( "abort" )); await expect( pactCaught ).resolves.toBe( "caught:abort" ); }); test( "windowing: pre-then observer sees its stage; post-then sees the chain", async () => { const [ pactA, fReportA ] = ftPact(() => undefined ); const vxStageA = []; const vxWhole = []; const pactDone = pactA .progress(( x ) => vxStageA.push( x )) .then(( s ) => new Pact(( fResolve, fReject, fReport ) => { fReport( "b1" ); fResolve( s + ":b" ); return () => undefined; })) .progress(( x ) => vxWhole.push( x )); fReportA( "a1" ); fReportA( "a2" ); await pactA.resolve( "a" ); await expect( pactDone ).resolves.toBe( "a:b" ); await fpTick(); expect( vxStageA ).toEqual([ "a1", "a2" ]); expect( vxWhole ).toEqual([ "a1", "a2", "b1" ]); } ); test( "releaseOn releases through an AbortController", async () => { let bCleaned = false; const controller = new AbortController(); const [ pact ] = ftPact(() => { bCleaned = true; }); pact.releaseOn( controller.signal ); controller.abort( "gone" ); await expect( pact ).resolves.toBe( "gone" ); expect( bCleaned ).toBe( true ); }); test( "releaseOn with a bare abort rejects by dispatch", async () => { const controller = new AbortController(); const [ pact ] = ftPact(() => undefined ); expect( pact.releaseOn( controller.signal )).toBe( pact ); controller.abort(); await expect( pact ).rejects.toThrow( /aborted/i ); }); test( "Pact.all reports members and releases as a group", async () => { const [ pact0, fReport0 ] = ftPact(() => undefined ); const [ pact1, fReport1 ] = ftPact(() => undefined ); const vaLog = []; const pactAll = Pact.all([ pact0, pact1 ]); pactAll.progress(( a ) => vaLog.push( a )); fReport0( "zero" ); fReport1( "one" ); await fpTick(); expect( vaLog ).toEqual([ { task : 0, report : "zero" }, { task : 1, report : "one" } ]); const aSettlement = await pactAll.release( new Pact.PactResolve( "stopped" ) ); expect( aSettlement ).toEqual({ sStatus : "resolved", x : "stopped" }); await expect( pactAll ).resolves.toBe( "stopped" ); fReport0( "late" ); await fpTick(); expect( vaLog ).toHaveLength( 2 ); });