From aa0a2e4b273086b135381fd1d94f791908aa465f Mon Sep 17 00:00:00 2001 From: Richie Bendall Date: Sun, 19 Jul 2020 01:54:40 +1200 Subject: [PATCH] Add `.range()` method (#51) Co-authored-by: Sindre Sorhus --- index.d.ts | 20 ++++++++++++++++++++ index.js | 4 ++++ index.test-d.ts | 2 ++ package.json | 5 ++++- readme.md | 8 ++++++++ test.js | 6 ++++++ 6 files changed, 44 insertions(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index 02ebd0e..8b45222 100644 --- a/index.d.ts +++ b/index.d.ts @@ -55,6 +55,26 @@ type Delay = { } ): delay.ClearablePromise; + /** + Create a promise which resolves after a random amount of milliseconds between `minimum` and `maximum` has passed. + + Useful for tests and web scraping since they can have unpredictable performance. For example, if you have a test that asserts a method should not take longer than a certain amount of time, and then run it on a CI, it could take longer. So with `.range()`, you could give it a threshold instead. + + @param minimum - Minimum amount of milliseconds to delay the promise. + @param maximum - Maximum amount of milliseconds to delay the promise. + @returns A promise which resolves after a random amount of milliseconds between `maximum` and `maximum` has passed. + */ + range( + minimum: number, + maximum: number, + options?: delay.Options & { + /** + Value to resolve in the returned promise. + */ + value: T; + } + ): delay.ClearablePromise; + /** Create a promise which rejects after the specified `milliseconds`. diff --git a/index.js b/index.js index 557bdbc..b863595 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,8 @@ 'use strict'; +// From https://github.com/sindresorhus/random-int/blob/c37741b56f76b9160b0b63dae4e9c64875128146/index.js#L13-L15 +const randomInteger = (minimum, maximum) => Math.floor((Math.random() * (maximum - minimum + 1)) + minimum); + const createAbortError = () => { const error = new Error('Delay aborted'); error.name = 'AbortError'; @@ -56,6 +59,7 @@ const createDelay = ({clearTimeout: defaultClear, setTimeout: set, willResolve}) const delay = createDelay({willResolve: true}); delay.reject = createDelay({willResolve: false}); +delay.range = (minimum, maximum, options) => delay(randomInteger(minimum, maximum), options); delay.createWithTimers = ({clearTimeout, setTimeout}) => { const delay = createDelay({clearTimeout, setTimeout, willResolve: true}); delay.reject = createDelay({clearTimeout, setTimeout, willResolve: false}); diff --git a/index.test-d.ts b/index.test-d.ts index 3999c2f..d41cc2b 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -11,6 +11,8 @@ expectType>( delay(200, {signal: new AbortController().signal}) ); +expectType>(delay.range(50, 200, {value: 0})); + expectType>(delay.reject(200, {value: '🦄'})); expectType>(delay.reject(200, {value: 0})); diff --git a/package.json b/package.json index 83786bd..f7e03ee 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,10 @@ "async", "await", "promises", - "bluebird" + "bluebird", + "threshold", + "range", + "random" ], "devDependencies": { "abort-controller": "^3.0.0", diff --git a/readme.md b/readme.md index 3d62fba..9a55098 100644 --- a/readme.md +++ b/readme.md @@ -36,7 +36,15 @@ Create a promise which resolves after the specified `milliseconds`. Create a promise which rejects after the specified `milliseconds`. +### delay.range(minimum, maximum, [options]) + +Create a promise which resolves after a random amount of milliseconds between `minimum` and `maximum` has passed. + +Useful for tests and web scraping since they can have unpredictable performance. For example, if you have a test that asserts a method should not take longer than a certain amount of time, and then run it on a CI, it could take longer. So with `.range()`, you could give it a threshold instead. + #### milliseconds +#### mininum +#### maximum Type: `number` diff --git a/test.js b/test.js index ed1b298..fec6caa 100644 --- a/test.js +++ b/test.js @@ -163,3 +163,9 @@ test('can create a new instance with fixed timeout methods', async t => { t.is(cleared.length, 1); t.is(cleared[0], callbacks[2].handle); }); + +test('returns a promise that is resolved in a random range of time', async t => { + const end = timeSpan(); + await m.range(50, 150); + t.true(inRange(end(), 30, 170), 'is delayed'); +});