Skip to content

Commit

Permalink
feature: implement timeout promise and timeout error
Browse files Browse the repository at this point in the history
  • Loading branch information
chendoron committed Dec 10, 2018
1 parent 2d1421b commit cff3fd7
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 8 deletions.
42 changes: 40 additions & 2 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,41 @@
const empty = () => {}
/**
* A custom error for when a TimeoutPromise rejects
* @param {number} delay - The delay which caused this error to be thrown
*/
class TimeoutError extends Error {
constructor(delay) {
super(`timeout after ${delay}ms`)
this.delay = delay
this.name = 'TimeoutError'
}
}

module.exports = empty
/**
* Wraps a Promise to rejects automatically after a certain
* amount of time, unless it already has been resolved or rejected.
* @param {number} delay - The delay in ms in which to reject the promise.
* @param {Promise} promise - The promise to wrap in a timeout rejection.
* @returns {Promise}
*/
class TimeoutPromise {
constructor(delay, promise) {
this.promise = new Promise((resolve, reject) => {
const timeout = setTimeout(() => reject(new TimeoutError(delay)), delay)
promise
.then((response) => {
clearTimeout(timeout)
return resolve(response)
})
.catch((rejection) => {
clearTimeout(timeout)
return reject(rejection)
})
})
return this.promise
}
}

module.exports = {
TimeoutError,
TimeoutPromise
}
99 changes: 93 additions & 6 deletions src/index.test.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,98 @@
const empty = require('.')
jest.useFakeTimers()

describe('index.js', () => {
it('exports a function', () => {
expect(empty).toBeInstanceOf(Function)
const { TimeoutError, TimeoutPromise } = require('.')

describe('utils/timeout-promise', () => {
describe('TimeoutError', () => {
const delay = 1000

it('is an error', () => {
const error = new TimeoutError(delay)

expect(error).toBeInstanceOf(Error)
})

it('has the correct properties', () => {
const error = new TimeoutError(delay)

expect(error.delay).toBe(delay)
expect(error.message).toBe(`timeout after ${delay}ms`)
})
})

it('returns nothing', () => {
expect(empty()).toBeUndefined()
describe('TimeoutPromise', () => {
const expectedValue = 'test value'
const asyncFunctionDelay = 5000
describe('wrap a resolving Promise with a TimeoutPromise', () => {
const resolvingPromiseFunction = jest.fn(
() =>
new Promise((resolve) =>
setTimeout(() => resolve(expectedValue), asyncFunctionDelay)
)
)

it('rejects with a timeout error', () => {
const timeoutPromiseDelay = 1000

const timeoutPromise = new TimeoutPromise(
timeoutPromiseDelay,
resolvingPromiseFunction()
)

jest.advanceTimersByTime(asyncFunctionDelay)

const expectedError = new TimeoutError(timeoutPromiseDelay)
expect(timeoutPromise).rejects.toThrow(expectedError)
})

it('resolves with a correct value', () => {
const timeoutPromiseDelay = 10000

const timeoutPromise = new TimeoutPromise(
timeoutPromiseDelay,
resolvingPromiseFunction()
)

jest.advanceTimersByTime(asyncFunctionDelay)

expect(timeoutPromise).resolves.toEqual(expectedValue)
})
})

describe('wrap a rejecting Promise with a TimeoutPromise', () => {
const rejectingPromiseFunction = jest.fn(
() =>
new Promise((resolve, reject) =>
setTimeout(() => reject(expectedValue), asyncFunctionDelay)
)
)

it('rejects with a timeout error', () => {
const timeoutPromiseDelay = 1000

const timeoutPromise = new TimeoutPromise(
timeoutPromiseDelay,
rejectingPromiseFunction()
)

jest.advanceTimersByTime(asyncFunctionDelay)

const expectedError = new TimeoutError(timeoutPromiseDelay)
expect(timeoutPromise).rejects.toThrow(expectedError)
})

it('resolves with a correct value', () => {
const timeoutPromiseDelay = 10000

const timeoutPromise = new TimeoutPromise(
timeoutPromiseDelay,
rejectingPromiseFunction()
)

jest.advanceTimersByTime(asyncFunctionDelay)

expect(timeoutPromise).rejects.toEqual(expectedValue)
})
})
})
})

0 comments on commit cff3fd7

Please sign in to comment.