From 89f299b244f2e494efbea97c9ff4425af23694df Mon Sep 17 00:00:00 2001 From: AndreasGassmann Date: Tue, 9 Jun 2020 08:54:24 +0000 Subject: [PATCH] fix(active-account): also set value if promise is not settled --- src/clients/client/Client.ts | 4 ++- src/clients/dapp-client/DAppClient.ts | 4 ++- src/utils/exposed-promise.ts | 30 ++++++++-------- test/utils/exposed-promise.spec.ts | 51 +++++++++++++++++++-------- 4 files changed, 57 insertions(+), 32 deletions(-) diff --git a/src/clients/client/Client.ts b/src/clients/client/Client.ts index ab2b7933a..e002bbe43 100644 --- a/src/clients/client/Client.ts +++ b/src/clients/client/Client.ts @@ -169,7 +169,9 @@ export abstract class Client extends BeaconClient { private async setTransport(transport: Transport): Promise { if (this._transport.isSettled()) { // If the promise has already been resolved we need to create a new one. - this._transport = new ExposedPromise({ result: transport }) + this._transport = ExposedPromise.resolve(transport) + } else { + this._transport.resolve(transport) } await this.events.emit(BeaconEvent.ACTIVE_TRANSPORT_SET, transport) diff --git a/src/clients/dapp-client/DAppClient.ts b/src/clients/dapp-client/DAppClient.ts index d9d2ae46d..7f9272dd3 100644 --- a/src/clients/dapp-client/DAppClient.ts +++ b/src/clients/dapp-client/DAppClient.ts @@ -130,7 +130,9 @@ export class DAppClient extends Client { public async setActiveAccount(account?: AccountInfo): Promise { if (this._activeAccount.isSettled()) { // If the promise has already been resolved we need to create a new one. - this._activeAccount = new ExposedPromise({ result: account }) + this._activeAccount = ExposedPromise.resolve(account) + } else { + this._activeAccount.resolve(account) } await this.storage.set( diff --git a/src/utils/exposed-promise.ts b/src/utils/exposed-promise.ts index a26cb119e..cb3e8cd88 100644 --- a/src/utils/exposed-promise.ts +++ b/src/utils/exposed-promise.ts @@ -7,16 +7,11 @@ export enum ExposedPromiseStatus { type Resolve = (value?: T) => void type Reject = (reason?: U) => void -interface ExposedPromiseOptions { - result?: T - error?: U -} - const notInitialized = (): never => { throw new Error('ExposedPromise not initialized yet.') } -export class ExposedPromise { +export class ExposedPromise { private readonly _promise: Promise private _resolve: Resolve = notInitialized @@ -45,7 +40,7 @@ export class ExposedPromise { return this._promiseError } - constructor(options?: ExposedPromiseOptions) { + constructor() { this._promise = new Promise((innerResolve: Resolve, innerReject: Reject): void => { this._resolve = (value?: T): void => { if (this.isSettled()) { @@ -74,15 +69,20 @@ export class ExposedPromise { return } }) + } - // Immediately resolve the promise if result or error have been passed - if (options && typeof options === 'object') { - if (options.hasOwnProperty('result')) { - this._resolve(options.result) - } else if (options.hasOwnProperty('error')) { - this._reject(options.error) - } - } + public static resolve(value?: T): ExposedPromise { + const promise = new ExposedPromise() + promise.resolve(value) + + return promise + } + + public static reject(reason?: U): ExposedPromise { + const promise = new ExposedPromise() + promise.reject(reason) + + return promise } public isPending(): boolean { diff --git a/test/utils/exposed-promise.spec.ts b/test/utils/exposed-promise.spec.ts index 2b6665c79..13aa60241 100644 --- a/test/utils/exposed-promise.spec.ts +++ b/test/utils/exposed-promise.spec.ts @@ -24,7 +24,7 @@ const cancelTimeoutAndSettle = ( } const getExpectedPromiseOutcome = ( - exposed: ExposedPromise, + exposed: ExposedPromise, expectedStatus: ExposedPromiseStatus ) => { const resolvePredicate = expectedStatus === ExposedPromiseStatus.RESOLVED @@ -95,29 +95,49 @@ describe.only(`ExposedPromise`, () => { expect(await Promise.all(promises)).to.deep.equal([undefined, undefined, undefined]) }) - it(`should create an empty ExposedPromise when passing an empty object`, async () => { - const exposed = new ExposedPromise({}) + it(`should correctly resolve an ExposedPromise`, async () => { + const exposed = new ExposedPromise() + const successMessage = 'success message!' + exposed.resolve(successMessage) - const promises = getExpectedPromiseOutcome(exposed, ExposedPromiseStatus.PENDING) + const promises = getExpectedPromiseOutcome(exposed, ExposedPromiseStatus.RESOLVED) expect(exposed instanceof ExposedPromise, 'is instanceof ExposedPromise').to.be.true - expect(exposed.isPending(), 'isPending').to.be.true - expect(exposed.isResolved(), 'isResolved').to.be.false + expect(exposed.isPending(), 'isPending').to.be.false + expect(exposed.isResolved(), 'isResolved').to.be.true expect(exposed.isRejected(), 'isRejected').to.be.false - expect(exposed.isSettled(), 'isSettled').to.be.false + expect(exposed.isSettled(), 'isSettled').to.be.true + expect(typeof exposed.promise, 'promise').to.equal('object') + expect(exposed.promiseResult, 'promiseResult').to.equal(successMessage) + expect(exposed.promiseError, 'promiseError').to.be.undefined + expect(exposed.status, 'status').to.equal(ExposedPromiseStatus.RESOLVED) + expect(typeof exposed.resolve, 'resolve').to.equal('function') + expect(typeof exposed.reject, 'reject').to.equal('function') + expect(await Promise.all(promises)).to.deep.equal(['success message!', undefined, undefined]) + }) + + it(`should create a resolved ExposedPromise when calling the static resolve`, async () => { + const exposed = ExposedPromise.resolve() + + const promises = getExpectedPromiseOutcome(exposed, ExposedPromiseStatus.RESOLVED) + + expect(exposed instanceof ExposedPromise, 'is instanceof ExposedPromise').to.be.true + expect(exposed.isPending(), 'isPending').to.be.false + expect(exposed.isResolved(), 'isResolved').to.be.true + expect(exposed.isRejected(), 'isRejected').to.be.false + expect(exposed.isSettled(), 'isSettled').to.be.true expect(typeof exposed.promise, 'promise').to.equal('object') expect(exposed.promiseResult, 'promiseResult').to.be.undefined expect(exposed.promiseError, 'promiseError').to.be.undefined - expect(exposed.status, 'status').to.equal(ExposedPromiseStatus.PENDING) + expect(exposed.status, 'status').to.equal(ExposedPromiseStatus.RESOLVED) expect(typeof exposed.resolve, 'resolve').to.equal('function') expect(typeof exposed.reject, 'reject').to.equal('function') expect(await Promise.all(promises)).to.deep.equal([undefined, undefined, undefined]) }) - it(`should correctly resolve an ExposedPromise`, async () => { - const exposed = new ExposedPromise() + it(`should create a resolved ExposedPromise when calling the static resolve with data`, async () => { const successMessage = 'success message!' - exposed.resolve(successMessage) + const exposed = ExposedPromise.resolve(successMessage) const promises = getExpectedPromiseOutcome(exposed, ExposedPromiseStatus.RESOLVED) @@ -181,7 +201,7 @@ describe.only(`ExposedPromise`, () => { it(`should resolve options.result immediately`, async () => { const successMessage = 'success message!' - const exposed = new ExposedPromise({ result: successMessage }) + const exposed = ExposedPromise.resolve(successMessage) const promises = getExpectedPromiseOutcome(exposed, ExposedPromiseStatus.RESOLVED) @@ -201,7 +221,7 @@ describe.only(`ExposedPromise`, () => { it(`should resolve options.result (undefined) immediately`, async () => { const successMessage = undefined - const exposed = new ExposedPromise({ result: successMessage }) + const exposed = ExposedPromise.resolve(successMessage) const promises = getExpectedPromiseOutcome(exposed, ExposedPromiseStatus.RESOLVED) @@ -270,7 +290,7 @@ describe.only(`ExposedPromise`, () => { it(`should reject options.reject immediately`, async () => { const failureMessage = 'failure message!' - const exposed = new ExposedPromise({ error: failureMessage }) + const exposed = ExposedPromise.reject(failureMessage) exposed.promise.catch(() => undefined) // We need to add a catch here or it will trigger an unhandled rejection error const promises = getExpectedPromiseOutcome(exposed, ExposedPromiseStatus.REJECTED) @@ -288,10 +308,11 @@ describe.only(`ExposedPromise`, () => { expect(typeof exposed.reject, 'reject').to.equal('function') expect(await Promise.all(promises)).to.deep.equal([undefined, 'failure message!', undefined]) }) + it(`should reject options.reject (undefined) immediately`, async () => { const failureMessage = 'failure message!' - const exposed = new ExposedPromise({ error: failureMessage }) + const exposed = ExposedPromise.reject(failureMessage) exposed.promise.catch(() => undefined) // We need to add a catch here or it will trigger an unhandled rejection error const promises = getExpectedPromiseOutcome(exposed, ExposedPromiseStatus.REJECTED)