diff --git a/packages/snipsonian-core/src/date/currentDate.ts b/packages/snipsonian-core/src/date/currentDate.ts new file mode 100644 index 00000000..785cdd27 --- /dev/null +++ b/packages/snipsonian-core/src/date/currentDate.ts @@ -0,0 +1,11 @@ +export function getCurrentDate() { + return new Date(); +} + +export function getCurrentYear(): number { + return getCurrentDate().getFullYear(); +} + +export function getCurrentTimestamp(): number { + return getCurrentDate().getTime(); +} diff --git a/packages/snipsonian-core/src/promise/extendPromise.test.ts b/packages/snipsonian-core/src/promise/extendPromise.test.ts new file mode 100644 index 00000000..36aa3bae --- /dev/null +++ b/packages/snipsonian-core/src/promise/extendPromise.test.ts @@ -0,0 +1,65 @@ +import extendPromise from './extendPromise'; +import isPromise from '../is/isPromise'; + +describe('extendPromise()', () => { + it('extends a given promise with the isPending and isResolved status functions', async () => { + const { testPromise, resolveTestPromise } = getTestPromise(); + expect(isPromise(testPromise)).toBe(true); + + const actual = extendPromise(testPromise); + + expect(isPromise(actual)).toEqual(true); + expect(actual.isPending()).toEqual(true); + expect(actual.isResolved()).toEqual(false); + expect(actual.isRejected()).toEqual(false); + + resolveTestPromise(); + + await actual; + + expect(actual.isPending()).toEqual(false); + expect(actual.isResolved()).toEqual(true); + expect(actual.isRejected()).toEqual(false); + }); + + it('extends a given promise with the isRejected status function', async () => { + const { testPromise, rejectTestPromise } = getTestPromise(); + + const actual = extendPromise(testPromise); + + expect(actual.isPending()).toEqual(true); + expect(actual.isResolved()).toEqual(false); + expect(actual.isRejected()).toEqual(false); + + rejectTestPromise(); + + try { + await actual; + } catch (error) { + expect(actual.isPending()).toEqual(false); + expect(actual.isResolved()).toEqual(false); + expect(actual.isRejected()).toEqual(true); + } + }); +}); + +function getTestPromise() { + let resolveTestPromise: () => void = null; + let rejectTestPromise: () => void = null; + + const testPromise = new Promise((resolve, reject) => { + resolveTestPromise = () => { + resolve(); + }; + + rejectTestPromise = () => { + reject(); + }; + }); + + return { + testPromise, + resolveTestPromise, + rejectTestPromise, + }; +} diff --git a/packages/snipsonian-core/src/promise/extendPromise.ts b/packages/snipsonian-core/src/promise/extendPromise.ts new file mode 100644 index 00000000..3a1c8717 --- /dev/null +++ b/packages/snipsonian-core/src/promise/extendPromise.ts @@ -0,0 +1,62 @@ +import { ONE_MINUTE_IN_MILLIS } from '../time/periodsInMillis'; +import { getCurrentTimestamp } from '../date/currentDate'; + +export interface IExtendedPromise extends Promise { + isPending: () => boolean; + isRejected: () => boolean; + isResolved: () => boolean; + wasResolvedPriorTo: (props: IWasResolvedPriorToProps) => boolean; + /* Returns the number of milliseconds since the promise was resolved. + Null if not resolved yet. */ + getMillisSinceResolved: () => number; +} + +interface IWasResolvedPriorToProps { + minutesAgo: number; +} + +/** + * As you can't see the status of a promise, here is a function to extend a given promise with some status functions. + */ +export default function extendPromise(promise: Promise): IExtendedPromise { + let promiseStatus = 'pending'; /* initial state */ + let resolveTimestamp: number = null; + + const extendedPromise = promise + .then((resolveData) => { + promiseStatus = 'resolved'; + resolveTimestamp = getCurrentTimestamp(); + + return resolveData; + }) + .catch((error) => { + promiseStatus = 'rejected'; + + throw error; + }) as IExtendedPromise; + + extendedPromise.isPending = () => promiseStatus === 'pending'; + extendedPromise.isRejected = () => promiseStatus === 'rejected'; + extendedPromise.isResolved = () => promiseStatus === 'resolved'; + + extendedPromise.wasResolvedPriorTo = ({ minutesAgo }: IWasResolvedPriorToProps): boolean => { + if (resolveTimestamp === null) { + return false; + } + + if (resolveTimestamp < (getCurrentTimestamp() - (minutesAgo * ONE_MINUTE_IN_MILLIS))) { + return true; + } + + return false; + }; + extendedPromise.getMillisSinceResolved = (): number => { + if (resolveTimestamp === null) { + return null; + } + + return (getCurrentTimestamp() - resolveTimestamp); + }; + + return extendedPromise; +} diff --git a/packages/snipsonian-core/src/testing/simulateWaitTime.ts b/packages/snipsonian-core/src/promise/simulateWaitTime.ts similarity index 91% rename from packages/snipsonian-core/src/testing/simulateWaitTime.ts rename to packages/snipsonian-core/src/promise/simulateWaitTime.ts index 70c3c6fb..9f32bf06 100644 --- a/packages/snipsonian-core/src/testing/simulateWaitTime.ts +++ b/packages/snipsonian-core/src/promise/simulateWaitTime.ts @@ -1,4 +1,4 @@ -export function simulateWaitTime({ +export default function simulateWaitTime({ waitTimeInMillis = 10, onWaited, }: { diff --git a/packages/snipsonian-core/src/promise/waitSeconds.ts b/packages/snipsonian-core/src/promise/waitSeconds.ts new file mode 100644 index 00000000..e5f1afcb --- /dev/null +++ b/packages/snipsonian-core/src/promise/waitSeconds.ts @@ -0,0 +1,8 @@ +import simulateWaitTime from './simulateWaitTime'; +import { ONE_SECOND_IN_MILLIS } from '../time/periodsInMillis'; + +export default function waitSeconds(nrOfSecondsToWait: number): Promise { + return simulateWaitTime({ + waitTimeInMillis: nrOfSecondsToWait * ONE_SECOND_IN_MILLIS, + }); +}