diff --git a/src/index.ts b/src/index.ts index 00c2960..f3d05d4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,3 +3,4 @@ export * from './communication'; export * from './dateTime'; export * from './geo'; export * from './arrays'; +export * from './utils'; diff --git a/src/utils/index.ts b/src/utils/index.ts new file mode 100644 index 0000000..f1e409a --- /dev/null +++ b/src/utils/index.ts @@ -0,0 +1 @@ +export * from './timeout'; diff --git a/src/utils/timeout.ts b/src/utils/timeout.ts index 1b16bcf..56a5cc0 100644 --- a/src/utils/timeout.ts +++ b/src/utils/timeout.ts @@ -1,3 +1,18 @@ export async function timeout(ms: number): Promise { return new Promise((resolve) => setTimeout(resolve, ms)); } + +export class TimeoutError extends Error {} + +export const racePromiseWithTimeout = async (msTimeout: number, promise: Promise): Promise => { + // Create a promise that rejects in milliseconds + const timeout = new Promise((_, reject) => { + const id = setTimeout(() => { + clearTimeout(id); + reject(new TimeoutError(`Timed out in + ${msTimeout} + ms.`)); + }, msTimeout); + }); + + // Returns a race between our timeout and the passed in promise + return Promise.race([promise, timeout]); +}; diff --git a/tests/configurations/unit/jest.config.js b/tests/configurations/unit/jest.config.js index ae290c3..af4c575 100644 --- a/tests/configurations/unit/jest.config.js +++ b/tests/configurations/unit/jest.config.js @@ -21,7 +21,7 @@ module.exports = { coverageThreshold: { global: { branches: 66, - functions: 94, + functions: 95, lines: 89, statements: 90, }, diff --git a/tests/unit/utils/timeout.spec.ts b/tests/unit/utils/timeout.spec.ts new file mode 100644 index 0000000..abc505b --- /dev/null +++ b/tests/unit/utils/timeout.spec.ts @@ -0,0 +1,26 @@ +import { TimeoutError, racePromiseWithTimeout } from './../../../src/utils'; + +describe('raceTimeout', () => { + it('should resolve with the promise value if it resolves before the timeout', async () => { + const value = 'test value'; + const promise = Promise.resolve(value); + const result = await racePromiseWithTimeout(1000, promise); + expect(result).toBe(value); + }); + + it("should reject with the promise's rejection reason if it rejects before the timeout", async () => { + const error = new Error('Test error'); + const promise = Promise.reject(error); + await expect(racePromiseWithTimeout(1000, promise)).rejects.toBe(error); + }); + + it('should reject with a TimeoutError if the promise takes longer than the timeout', async () => { + const promise = new Promise((resolve) => { + setTimeout(() => { + resolve('success'); + }, 300); + }); + + await expect(racePromiseWithTimeout(200, promise)).rejects.toThrow(TimeoutError); + }); +}); diff --git a/tsconfig.json b/tsconfig.json index 42605db..f42c3b8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "es5", + "target": "es2022", "allowSyntheticDefaultImports": true, "strict": true, "module": "commonjs",