The problem. A pipeline with delay: '2s' retries and a breakDuration: '30s' breaker is slow to test with a real clock.
Tests either wait (slow), or shrink every duration to a few milliseconds (flaky on a busy CI machine, and no longer the configuration you ship).
The solution. Every strategy reads time through a TimeProvider. In tests, pass a FakeTimeProvider from
resilience-pipeline/testing and move the clock by hand. A test of “three retries 10 s apart, then a 1 s timeout” finishes in
a few milliseconds and does exactly the same thing every run.
The test() function is the value imported from the test module. Each
invocation of this function results in reporting the test to the TestsStream.
The TestContext object passed to the fn argument can be used to perform
actions related to the current test. Examples include skipping the test, adding
additional diagnostic information, or creating subtests.
test() returns a Promise that fulfills once the test completes.
if test() is called within a suite, it fulfills immediately.
The return value can usually be discarded for top level tests.
However, the return value from subtests should be used to prevent the parent
test from finishing first and cancelling the subtest
as shown in the following example.
test('top level test', async (t) => {
// The setTimeout() in the following subtest would cause it to outlive its
// parent test if 'await' is removed on the next line. Once the parent test
// completes, it will cancel any outstanding subtests.
The timeout option can be used to fail the test if it takes longer than timeout milliseconds to complete. However, it is not a reliable mechanism for
canceling tests because a running test might block the application thread and
thus prevent the scheduled cancellation.
@since ― v18.0.0, v16.17.0
@param ― name The name of the test, which is displayed when reporting test results.
Defaults to the name property of fn, or '<anonymous>' if fn does not have a name.
@param ― options Configuration options for the test.
@param ― fn The function under test. The first argument to this function is a TestContext object.
If the test uses callbacks, the callback function is passed as the second argument.
@return ― Fulfilled with undefined once the test completes, or immediately if the test runs within a suite.
Polly-style builder with a shortcut for every strategy: addRetry(), addTimeout(), addCircuitBreaker(), …
Convenient, but it bundles every strategy. For the smallest browser bundle use PipelineBuilder with
retryStrategy(), timeoutStrategy(), … instead; the two are interchangeable.
The type parameters track which errors the pipeline can raise, for pipeline.settle() + Outcome.match().
ResiliencePipelineBuilder,
classTimeoutRejectedError
TimeoutRejectedError } from'resilience-pipeline';
import {
classFakeTimeProvider
A clock you move by hand, so retries, timeouts and open circuits can be tested without waiting.
consttime=newFakeTimeProvider();
constpipeline=newResiliencePipelineBuilder({ timeProvider: time }).addRetry({ delay: '10s' }).addTimeout('1s').build();
// Attach the expectation first: the promise settles while runAll() fires timers.
The test() function is the value imported from the test module. Each
invocation of this function results in reporting the test to the TestsStream.
The TestContext object passed to the fn argument can be used to perform
actions related to the current test. Examples include skipping the test, adding
additional diagnostic information, or creating subtests.
test() returns a Promise that fulfills once the test completes.
if test() is called within a suite, it fulfills immediately.
The return value can usually be discarded for top level tests.
However, the return value from subtests should be used to prevent the parent
test from finishing first and cancelling the subtest
as shown in the following example.
test('top level test', async (t) => {
// The setTimeout() in the following subtest would cause it to outlive its
// parent test if 'await' is removed on the next line. Once the parent test
// completes, it will cancel any outstanding subtests.
The timeout option can be used to fail the test if it takes longer than timeout milliseconds to complete. However, it is not a reliable mechanism for
canceling tests because a running test might block the application thread and
thus prevent the scheduled cancellation.
@since ― v18.0.0, v16.17.0
@param ― name The name of the test, which is displayed when reporting test results.
Defaults to the name property of fn, or '<anonymous>' if fn does not have a name.
@param ― options Configuration options for the test.
@param ― fn The function under test. The first argument to this function is a TestContext object.
If the test uses callbacks, the callback function is passed as the second argument.
@return ― Fulfilled with undefined once the test completes, or immediately if the test runs within a suite.
test('gives up after 3 retries and 4 timeouts', async () => {
const
consttime:FakeTimeProvider
time=new
newFakeTimeProvider(start?: number | Date): FakeTimeProvider
A clock you move by hand, so retries, timeouts and open circuits can be tested without waiting.
consttime=newFakeTimeProvider();
constpipeline=newResiliencePipelineBuilder({ timeProvider: time }).addRetry({ delay: '10s' }).addTimeout('1s').build();
// Attach the expectation first: the promise settles while runAll() fires timers.
Polly-style builder with a shortcut for every strategy: addRetry(), addTimeout(), addCircuitBreaker(), …
Convenient, but it bundles every strategy. For the smallest browser bundle use PipelineBuilder with
retryStrategy(), timeoutStrategy(), … instead; the two are interchangeable.
The type parameters track which errors the pipeline can raise, for pipeline.settle() + Outcome.match().
Awaits the asyncFn promise or, if asyncFn is a function, immediately
calls the function and awaits the returned promise to complete. It will then
check that the promise is rejected.
If asyncFn is a function and it throws an error synchronously, assert.rejects() will return a rejected Promise with that error. If the
function does not return a promise, assert.rejects() will return a rejected Promise with an ERR_INVALID_RETURN_VALUE
error. In both cases the error handler is skipped.
Besides the async nature to await the completion behaves identically to
throws
.
If specified, error can be a Class,
RegExp, a validation function,
an object where each property will be tested for, or an instance of error where
each property will be tested for including the non-enumerable message and name properties.
If specified, message will be the message provided by the `
AssertionError
if theasyncFn` fails to reject.
import assert from'node:assert/strict';
await assert.rejects(
async () => {
thrownewTypeError('Wrong value');
},
{
name: 'TypeError',
message: 'Wrong value',
},
);
import assert from'node:assert/strict';
await assert.rejects(
async () => {
thrownewTypeError('Wrong value');
},
(err) => {
assert.strictEqual(err.name, 'TypeError');
assert.strictEqual(err.message, 'Wrong value');
returntrue;
},
);
import assert from'node:assert/strict';
assert.rejects(
Promise.reject(newError('Wrong value')),
Error,
).then(() => {
// ...
});
error cannot be a string. If a string is provided as the second argument, then error is assumed to
be omitted and the string will be used for message instead. This can lead to easy-to-miss mistakes. Please read the
example in
throws
carefully if using a string as the second argument gets considered.
Runs the callback through the pipeline; throws the final error.
execute(() =>new
var Promise:PromiseConstructor
new <unknown>(executor: (resolve: (value:unknown) =>void, reject: (reason?:any) =>void) =>void) =>Promise<unknown>
Creates a new Promise.
@param ― executor A callback used to initialize the promise. This callback is passed two arguments:
a resolve callback used to resolve the promise with a value or the result of another promise,
and a reject callback used to reject the promise with a provided reason or error.
Promise(() => {})),
classTimeoutRejectedError
TimeoutRejectedError);
// 2. Fire every timer: 4 timeouts of 1 s + 3 delays of 10 s.
// AssertionError [ERR_ASSERTION]: apples 1 !== oranges 2
assert.strictEqual(1, '1', newTypeError('Inputs are not identical'));
// TypeError: Inputs are not identical
If the values are not strictly equal, an AssertionError is thrown with a message property set equal to the value of the message parameter. If the message parameter is undefined, a
default error message is assigned. If the message parameter is an instance of an Error then it will be thrown
instead of the AssertionError.
@since ― v0.1.21
equal(
consttime:FakeTimeProvider
time.
FakeTimeProvider.now(): number
Epoch milliseconds.
now() -
conststart:number
start, 34_000);
});
FakeTimeProvider has three controls:
Member
What it does
advance(duration)
Moves the clock forward by duration ('30s', 500…), firing every timer that comes due, in order.
runAll(limit = 10_000)
Fires timers until none are left, including timers scheduled while firing. Throws after limit timers.
pendingTimers
How many timers are scheduled and not fired yet. 0 at the end of a test means nothing is left running.
The clock starts at 2026-01-01T00:00:00Z. Pass new FakeTimeProvider(0) or a Date to start elsewhere.
Between two timers, the fake clock yields to the event loop with a real setTimeout(0), so every promise continuation
(your callback’s awaits, the strategies’ own) runs before the next timer fires.
pipeline.execute() can’t settle until its timers fire. Two ways to get this wrong:
await pipeline.execute(...) first, then time.runAll(): the test hangs. The await never returns, because nothing moves the clock.
Start the call without a handler, then await time.runAll(): the call rejects duringrunAll(), while nothing is
listening. Node reports an unhandled rejection and fails the test run.
So the order is always: start the call, attach the handler (assert.rejects(promise), promise.catch(...), or just keep the
promise for a later await if it resolves), then move the clock, then await.
The test() function is the value imported from the test module. Each
invocation of this function results in reporting the test to the TestsStream.
The TestContext object passed to the fn argument can be used to perform
actions related to the current test. Examples include skipping the test, adding
additional diagnostic information, or creating subtests.
test() returns a Promise that fulfills once the test completes.
if test() is called within a suite, it fulfills immediately.
The return value can usually be discarded for top level tests.
However, the return value from subtests should be used to prevent the parent
test from finishing first and cancelling the subtest
as shown in the following example.
test('top level test', async (t) => {
// The setTimeout() in the following subtest would cause it to outlive its
// parent test if 'await' is removed on the next line. Once the parent test
// completes, it will cancel any outstanding subtests.
The timeout option can be used to fail the test if it takes longer than timeout milliseconds to complete. However, it is not a reliable mechanism for
canceling tests because a running test might block the application thread and
thus prevent the scheduled cancellation.
@since ― v18.0.0, v16.17.0
@param ― name The name of the test, which is displayed when reporting test results.
Defaults to the name property of fn, or '<anonymous>' if fn does not have a name.
@param ― options Configuration options for the test.
@param ― fn The function under test. The first argument to this function is a TestContext object.
If the test uses callbacks, the callback function is passed as the second argument.
@return ― Fulfilled with undefined once the test completes, or immediately if the test runs within a suite.
Polly-style builder with a shortcut for every strategy: addRetry(), addTimeout(), addCircuitBreaker(), …
Convenient, but it bundles every strategy. For the smallest browser bundle use PipelineBuilder with
retryStrategy(), timeoutStrategy(), … instead; the two are interchangeable.
The type parameters track which errors the pipeline can raise, for pipeline.settle() + Outcome.match().
The test() function is the value imported from the test module. Each
invocation of this function results in reporting the test to the TestsStream.
The TestContext object passed to the fn argument can be used to perform
actions related to the current test. Examples include skipping the test, adding
additional diagnostic information, or creating subtests.
test() returns a Promise that fulfills once the test completes.
if test() is called within a suite, it fulfills immediately.
The return value can usually be discarded for top level tests.
However, the return value from subtests should be used to prevent the parent
test from finishing first and cancelling the subtest
as shown in the following example.
test('top level test', async (t) => {
// The setTimeout() in the following subtest would cause it to outlive its
// parent test if 'await' is removed on the next line. Once the parent test
// completes, it will cancel any outstanding subtests.
The timeout option can be used to fail the test if it takes longer than timeout milliseconds to complete. However, it is not a reliable mechanism for
canceling tests because a running test might block the application thread and
thus prevent the scheduled cancellation.
@since ― v18.0.0, v16.17.0
@param ― name The name of the test, which is displayed when reporting test results.
Defaults to the name property of fn, or '<anonymous>' if fn does not have a name.
@param ― options Configuration options for the test.
@param ― fn The function under test. The first argument to this function is a TestContext object.
If the test uses callbacks, the callback function is passed as the second argument.
@return ― Fulfilled with undefined once the test completes, or immediately if the test runs within a suite.
test('retries exactly 10 s apart', async () => {
const
consttime:FakeTimeProvider
time=new
newFakeTimeProvider(start?: number | Date): FakeTimeProvider
A clock you move by hand, so retries, timeouts and open circuits can be tested without waiting.
consttime=newFakeTimeProvider();
constpipeline=newResiliencePipelineBuilder({ timeProvider: time }).addRetry({ delay: '10s' }).addTimeout('1s').build();
// Attach the expectation first: the promise settles while runAll() fires timers.
Polly-style builder with a shortcut for every strategy: addRetry(), addTimeout(), addCircuitBreaker(), …
Convenient, but it bundles every strategy. For the smallest browser bundle use PipelineBuilder with
retryStrategy(), timeoutStrategy(), … instead; the two are interchangeable.
The type parameters track which errors the pipeline can raise, for pipeline.settle() + Outcome.match().
// AssertionError [ERR_ASSERTION]: apples 1 !== oranges 2
assert.strictEqual(1, '1', newTypeError('Inputs are not identical'));
// TypeError: Inputs are not identical
If the values are not strictly equal, an AssertionError is thrown with a message property set equal to the value of the message parameter. If the message parameter is undefined, a
default error message is assigned. If the message parameter is an instance of an Error then it will be thrown
instead of the AssertionError.
// AssertionError [ERR_ASSERTION]: apples 1 !== oranges 2
assert.strictEqual(1, '1', newTypeError('Inputs are not identical'));
// TypeError: Inputs are not identical
If the values are not strictly equal, an AssertionError is thrown with a message property set equal to the value of the message parameter. If the message parameter is undefined, a
default error message is assigned. If the message parameter is an instance of an Error then it will be thrown
instead of the AssertionError.
// AssertionError [ERR_ASSERTION]: apples 1 !== oranges 2
assert.strictEqual(1, '1', newTypeError('Inputs are not identical'));
// TypeError: Inputs are not identical
If the values are not strictly equal, an AssertionError is thrown with a message property set equal to the value of the message parameter. If the message parameter is undefined, a
default error message is assigned. If the message parameter is an instance of an Error then it will be thrown
instead of the AssertionError.
// AssertionError [ERR_ASSERTION]: apples 1 !== oranges 2
assert.strictEqual(1, '1', newTypeError('Inputs are not identical'));
// TypeError: Inputs are not identical
If the values are not strictly equal, an AssertionError is thrown with a message property set equal to the value of the message parameter. If the message parameter is undefined, a
default error message is assigned. If the message parameter is an instance of an Error then it will be thrown
instead of the AssertionError.
// AssertionError [ERR_ASSERTION]: apples 1 !== oranges 2
assert.strictEqual(1, '1', newTypeError('Inputs are not identical'));
// TypeError: Inputs are not identical
If the values are not strictly equal, an AssertionError is thrown with a message property set equal to the value of the message parameter. If the message parameter is undefined, a
default error message is assigned. If the message parameter is an instance of an Error then it will be thrown
instead of the AssertionError.
// AssertionError [ERR_ASSERTION]: apples 1 !== oranges 2
assert.strictEqual(1, '1', newTypeError('Inputs are not identical'));
// TypeError: Inputs are not identical
If the values are not strictly equal, an AssertionError is thrown with a message property set equal to the value of the message parameter. If the message parameter is undefined, a
default error message is assigned. If the message parameter is an instance of an Error then it will be thrown
instead of the AssertionError.
Polly-style builder with a shortcut for every strategy: addRetry(), addTimeout(), addCircuitBreaker(), …
Convenient, but it bundles every strategy. For the smallest browser bundle use PipelineBuilder with
retryStrategy(), timeoutStrategy(), … instead; the two are interchangeable.
The type parameters track which errors the pipeline can raise, for pipeline.settle() + Outcome.match().
ResiliencePipelineBuilder, type
(alias) interfaceTimeProvider
importTimeProvider
Clock and timers used by every strategy. Swap it for FakeTimeProvider (resilience-pipeline/testing) to test without waiting.
Polly-style builder with a shortcut for every strategy: addRetry(), addTimeout(), addCircuitBreaker(), …
Convenient, but it bundles every strategy. For the smallest browser bundle use PipelineBuilder with
retryStrategy(), timeoutStrategy(), … instead; the two are interchangeable.
The type parameters track which errors the pipeline can raise, for pipeline.settle() + Outcome.match().
ResiliencePipelineBuilder<
interfaceResponse
The Response interface of the Fetch API represents the response to a request.
CircuitBreakerOptions<Response>.consecutiveFailures?: number |undefined
Break after this many failures in a row (a success resets the count). Simple and good for low traffic.
When set without failureRatio, the ratio check is off and only this rule applies.
Polly-style builder with a shortcut for every strategy: addRetry(), addTimeout(), addCircuitBreaker(), …
Convenient, but it bundles every strategy. For the smallest browser bundle use PipelineBuilder with
retryStrategy(), timeoutStrategy(), … instead; the two are interchangeable.
The type parameters track which errors the pipeline can raise, for pipeline.settle() + Outcome.match().
The test() function is the value imported from the test module. Each
invocation of this function results in reporting the test to the TestsStream.
The TestContext object passed to the fn argument can be used to perform
actions related to the current test. Examples include skipping the test, adding
additional diagnostic information, or creating subtests.
test() returns a Promise that fulfills once the test completes.
if test() is called within a suite, it fulfills immediately.
The return value can usually be discarded for top level tests.
However, the return value from subtests should be used to prevent the parent
test from finishing first and cancelling the subtest
as shown in the following example.
test('top level test', async (t) => {
// The setTimeout() in the following subtest would cause it to outlive its
// parent test if 'await' is removed on the next line. Once the parent test
// completes, it will cancel any outstanding subtests.
The timeout option can be used to fail the test if it takes longer than timeout milliseconds to complete. However, it is not a reliable mechanism for
canceling tests because a running test might block the application thread and
thus prevent the scheduled cancellation.
@since ― v18.0.0, v16.17.0
@param ― name The name of the test, which is displayed when reporting test results.
Defaults to the name property of fn, or '<anonymous>' if fn does not have a name.
@param ― options Configuration options for the test.
@param ― fn The function under test. The first argument to this function is a TestContext object.
If the test uses callbacks, the callback function is passed as the second argument.
@return ― Fulfilled with undefined once the test completes, or immediately if the test runs within a suite.
test('times out on a hanging dependency', async () => {
const
consttime:FakeTimeProvider
time=new
newFakeTimeProvider(start?: number | Date): FakeTimeProvider
A clock you move by hand, so retries, timeouts and open circuits can be tested without waiting.
consttime=newFakeTimeProvider();
constpipeline=newResiliencePipelineBuilder({ timeProvider: time }).addRetry({ delay: '10s' }).addTimeout('1s').build();
// Attach the expectation first: the promise settles while runAll() fires timers.
Awaits the asyncFn promise or, if asyncFn is a function, immediately
calls the function and awaits the returned promise to complete. It will then
check that the promise is rejected.
If asyncFn is a function and it throws an error synchronously, assert.rejects() will return a rejected Promise with that error. If the
function does not return a promise, assert.rejects() will return a rejected Promise with an ERR_INVALID_RETURN_VALUE
error. In both cases the error handler is skipped.
Besides the async nature to await the completion behaves identically to
throws
.
If specified, error can be a Class,
RegExp, a validation function,
an object where each property will be tested for, or an instance of error where
each property will be tested for including the non-enumerable message and name properties.
If specified, message will be the message provided by the `
AssertionError
if theasyncFn` fails to reject.
import assert from'node:assert/strict';
await assert.rejects(
async () => {
thrownewTypeError('Wrong value');
},
{
name: 'TypeError',
message: 'Wrong value',
},
);
import assert from'node:assert/strict';
await assert.rejects(
async () => {
thrownewTypeError('Wrong value');
},
(err) => {
assert.strictEqual(err.name, 'TypeError');
assert.strictEqual(err.message, 'Wrong value');
returntrue;
},
);
import assert from'node:assert/strict';
assert.rejects(
Promise.reject(newError('Wrong value')),
Error,
).then(() => {
// ...
});
error cannot be a string. If a string is provided as the second argument, then error is assumed to
be omitted and the string will be used for message instead. This can lead to easy-to-miss mistakes. Please read the
example in
throws
carefully if using a string as the second argument gets considered.
Runs the callback through the pipeline; throws the final error.
execute(() =>new
var Promise:PromiseConstructor
new <unknown>(executor: (resolve: (value:unknown) =>void, reject: (reason?:any) =>void) =>void) =>Promise<unknown>
Creates a new Promise.
@param ― executor A callback used to initialize the promise. This callback is passed two arguments:
a resolve callback used to resolve the promise with a value or the result of another promise,
and a reject callback used to reject the promise with a provided reason or error.
Fires timers until none are left (including ones scheduled while firing). Throws after limit timers to catch infinite loops.
runAll();
await
constdone:Promise<void>
done;
});
The per-execution clock drives that execution’s own timing only: retry delays, timeouts, hedging delays and chaos latency.
Stateful strategies (circuit breakers, rate limiters, caches, locks) keep the pipeline’s clock, because their state spans
many executions. To test a breaker’s breakDuration or a limiter’s refill, give the builder the fake clock.
Three tools make breaker tests exact: consecutiveFailures (opens after N failures in a row, no ratio math),
CircuitBreakerStateProvider (read the state), and nextTelemetry (wait for an event).
The test() function is the value imported from the test module. Each
invocation of this function results in reporting the test to the TestsStream.
The TestContext object passed to the fn argument can be used to perform
actions related to the current test. Examples include skipping the test, adding
additional diagnostic information, or creating subtests.
test() returns a Promise that fulfills once the test completes.
if test() is called within a suite, it fulfills immediately.
The return value can usually be discarded for top level tests.
However, the return value from subtests should be used to prevent the parent
test from finishing first and cancelling the subtest
as shown in the following example.
test('top level test', async (t) => {
// The setTimeout() in the following subtest would cause it to outlive its
// parent test if 'await' is removed on the next line. Once the parent test
// completes, it will cancel any outstanding subtests.
The timeout option can be used to fail the test if it takes longer than timeout milliseconds to complete. However, it is not a reliable mechanism for
canceling tests because a running test might block the application thread and
thus prevent the scheduled cancellation.
@since ― v18.0.0, v16.17.0
@param ― name The name of the test, which is displayed when reporting test results.
Defaults to the name property of fn, or '<anonymous>' if fn does not have a name.
@param ― options Configuration options for the test.
@param ― fn The function under test. The first argument to this function is a TestContext object.
If the test uses callbacks, the callback function is passed as the second argument.
@return ― Fulfilled with undefined once the test completes, or immediately if the test runs within a suite.
Polly-style builder with a shortcut for every strategy: addRetry(), addTimeout(), addCircuitBreaker(), …
Convenient, but it bundles every strategy. For the smallest browser bundle use PipelineBuilder with
retryStrategy(), timeoutStrategy(), … instead; the two are interchangeable.
The type parameters track which errors the pipeline can raise, for pipeline.settle() + Outcome.match().
The test() function is the value imported from the test module. Each
invocation of this function results in reporting the test to the TestsStream.
The TestContext object passed to the fn argument can be used to perform
actions related to the current test. Examples include skipping the test, adding
additional diagnostic information, or creating subtests.
test() returns a Promise that fulfills once the test completes.
if test() is called within a suite, it fulfills immediately.
The return value can usually be discarded for top level tests.
However, the return value from subtests should be used to prevent the parent
test from finishing first and cancelling the subtest
as shown in the following example.
test('top level test', async (t) => {
// The setTimeout() in the following subtest would cause it to outlive its
// parent test if 'await' is removed on the next line. Once the parent test
// completes, it will cancel any outstanding subtests.
The timeout option can be used to fail the test if it takes longer than timeout milliseconds to complete. However, it is not a reliable mechanism for
canceling tests because a running test might block the application thread and
thus prevent the scheduled cancellation.
@since ― v18.0.0, v16.17.0
@param ― name The name of the test, which is displayed when reporting test results.
Defaults to the name property of fn, or '<anonymous>' if fn does not have a name.
@param ― options Configuration options for the test.
@param ― fn The function under test. The first argument to this function is a TestContext object.
If the test uses callbacks, the callback function is passed as the second argument.
@return ― Fulfilled with undefined once the test completes, or immediately if the test runs within a suite.
test('opens after 3 failures, probes after 30 s, closes on success', async () => {
const
consttime:FakeTimeProvider
time=new
newFakeTimeProvider(start?: number | Date): FakeTimeProvider
A clock you move by hand, so retries, timeouts and open circuits can be tested without waiting.
consttime=newFakeTimeProvider();
constpipeline=newResiliencePipelineBuilder({ timeProvider: time }).addRetry({ delay: '10s' }).addTimeout('1s').build();
// Attach the expectation first: the promise settles while runAll() fires timers.
Polly-style builder with a shortcut for every strategy: addRetry(), addTimeout(), addCircuitBreaker(), …
Convenient, but it bundles every strategy. For the smallest browser bundle use PipelineBuilder with
retryStrategy(), timeoutStrategy(), … instead; the two are interchangeable.
The type parameters track which errors the pipeline can raise, for pipeline.settle() + Outcome.match().
CircuitBreakerOptions<any>.consecutiveFailures?: number |undefined
Break after this many failures in a row (a success resets the count). Simple and good for low traffic.
When set without failureRatio, the ratio check is off and only this rule applies.
Awaits the asyncFn promise or, if asyncFn is a function, immediately
calls the function and awaits the returned promise to complete. It will then
check that the promise is rejected.
If asyncFn is a function and it throws an error synchronously, assert.rejects() will return a rejected Promise with that error. If the
function does not return a promise, assert.rejects() will return a rejected Promise with an ERR_INVALID_RETURN_VALUE
error. In both cases the error handler is skipped.
Besides the async nature to await the completion behaves identically to
throws
.
If specified, error can be a Class,
RegExp, a validation function,
an object where each property will be tested for, or an instance of error where
each property will be tested for including the non-enumerable message and name properties.
If specified, message will be the message provided by the `
AssertionError
if theasyncFn` fails to reject.
import assert from'node:assert/strict';
await assert.rejects(
async () => {
thrownewTypeError('Wrong value');
},
{
name: 'TypeError',
message: 'Wrong value',
},
);
import assert from'node:assert/strict';
await assert.rejects(
async () => {
thrownewTypeError('Wrong value');
},
(err) => {
assert.strictEqual(err.name, 'TypeError');
assert.strictEqual(err.message, 'Wrong value');
returntrue;
},
);
import assert from'node:assert/strict';
assert.rejects(
Promise.reject(newError('Wrong value')),
Error,
).then(() => {
// ...
});
error cannot be a string. If a string is provided as the second argument, then error is assumed to
be omitted and the string will be used for message instead. This can lead to easy-to-miss mistakes. Please read the
example in
throws
carefully if using a string as the second argument gets considered.
// AssertionError [ERR_ASSERTION]: apples 1 !== oranges 2
assert.strictEqual(1, '1', newTypeError('Inputs are not identical'));
// TypeError: Inputs are not identical
If the values are not strictly equal, an AssertionError is thrown with a message property set equal to the value of the message parameter. If the message parameter is undefined, a
default error message is assigned. If the message parameter is an instance of an Error then it will be thrown
instead of the AssertionError.
strict.ok(value: unknown, message?: string | Error): asserts value
export strict.ok
Tests if value is truthy. It is equivalent to assert.equal(!!value, true, message).
If value is not truthy, an AssertionError is thrown with a message property set equal to the value of the message parameter. If the message parameter is undefined, a default
error message is assigned. If the message parameter is an instance of an Error then it will be thrown instead of the AssertionError.
If no arguments are passed in at all message will be set to the string:'No value argument passed to `assert.ok()`'.
Be aware that in the repl the error message will be different to the one
thrown in a file! See below for further details.
import assert from'node:assert/strict';
assert.ok(true);
// OK
assert.ok(1);
// OK
assert.ok();
// AssertionError: No value argument passed to `assert.ok()`
assert.ok(false, 'it\'s false');
// AssertionError: it's false
// In the repl:
assert.ok(typeof123==='string');
// AssertionError: false == true
// In a file (e.g. test.js):
assert.ok(typeof123==='string');
// AssertionError: The expression evaluated to a falsy value:
//
// assert.ok(typeof 123 === 'string')
assert.ok(false);
// AssertionError: The expression evaluated to a falsy value:
//
// assert.ok(false)
assert.ok(0);
// AssertionError: The expression evaluated to a falsy value:
//
// assert.ok(0)
import assert from'node:assert/strict';
// Using `assert()` works the same:
assert(0);
// AssertionError: The expression evaluated to a falsy value:
// AssertionError [ERR_ASSERTION]: apples 1 !== oranges 2
assert.strictEqual(1, '1', newTypeError('Inputs are not identical'));
// TypeError: Inputs are not identical
If the values are not strictly equal, an AssertionError is thrown with a message property set equal to the value of the message parameter. If the message parameter is undefined, a
default error message is assigned. If the message parameter is an instance of an Error then it will be thrown
instead of the AssertionError.
@since ― v0.1.21
equal(
constrefused:BrokenCircuitError
refused.
BrokenCircuitError.retryAfter: number |undefined
Milliseconds until the circuit allows a probe call.
retryAfter, 30_000);
// After the break, the next call is the half-open probe.
// AssertionError [ERR_ASSERTION]: apples 1 !== oranges 2
assert.strictEqual(1, '1', newTypeError('Inputs are not identical'));
// TypeError: Inputs are not identical
If the values are not strictly equal, an AssertionError is thrown with a message property set equal to the value of the message parameter. If the message parameter is undefined, a
default error message is assigned. If the message parameter is an instance of an Error then it will be thrown
instead of the AssertionError.
// AssertionError [ERR_ASSERTION]: apples 1 !== oranges 2
assert.strictEqual(1, '1', newTypeError('Inputs are not identical'));
// TypeError: Inputs are not identical
If the values are not strictly equal, an AssertionError is thrown with a message property set equal to the value of the message parameter. If the message parameter is undefined, a
default error message is assigned. If the message parameter is an instance of an Error then it will be thrown
instead of the AssertionError.
@since ― v0.1.21
equal(
conststate:CircuitBreakerStateProvider
state.
CircuitBreakerStateProvider.circuitState: "open"
circuitState, 'closed');
});
To start a test from a given state, use the live strategy: pipeline.getStrategy<CircuitBreakerStrategy<any>>('CircuitBreaker')
has trip() (open for the break duration) and reset() (close and clear the window).
The test() function is the value imported from the test module. Each
invocation of this function results in reporting the test to the TestsStream.
The TestContext object passed to the fn argument can be used to perform
actions related to the current test. Examples include skipping the test, adding
additional diagnostic information, or creating subtests.
test() returns a Promise that fulfills once the test completes.
if test() is called within a suite, it fulfills immediately.
The return value can usually be discarded for top level tests.
However, the return value from subtests should be used to prevent the parent
test from finishing first and cancelling the subtest
as shown in the following example.
test('top level test', async (t) => {
// The setTimeout() in the following subtest would cause it to outlive its
// parent test if 'await' is removed on the next line. Once the parent test
// completes, it will cancel any outstanding subtests.
The timeout option can be used to fail the test if it takes longer than timeout milliseconds to complete. However, it is not a reliable mechanism for
canceling tests because a running test might block the application thread and
thus prevent the scheduled cancellation.
@since ― v18.0.0, v16.17.0
@param ― name The name of the test, which is displayed when reporting test results.
Defaults to the name property of fn, or '<anonymous>' if fn does not have a name.
@param ― options Configuration options for the test.
@param ― fn The function under test. The first argument to this function is a TestContext object.
If the test uses callbacks, the callback function is passed as the second argument.
@return ― Fulfilled with undefined once the test completes, or immediately if the test runs within a suite.
Polly-style builder with a shortcut for every strategy: addRetry(), addTimeout(), addCircuitBreaker(), …
Convenient, but it bundles every strategy. For the smallest browser bundle use PipelineBuilder with
retryStrategy(), timeoutStrategy(), … instead; the two are interchangeable.
The type parameters track which errors the pipeline can raise, for pipeline.settle() + Outcome.match().
The test() function is the value imported from the test module. Each
invocation of this function results in reporting the test to the TestsStream.
The TestContext object passed to the fn argument can be used to perform
actions related to the current test. Examples include skipping the test, adding
additional diagnostic information, or creating subtests.
test() returns a Promise that fulfills once the test completes.
if test() is called within a suite, it fulfills immediately.
The return value can usually be discarded for top level tests.
However, the return value from subtests should be used to prevent the parent
test from finishing first and cancelling the subtest
as shown in the following example.
test('top level test', async (t) => {
// The setTimeout() in the following subtest would cause it to outlive its
// parent test if 'await' is removed on the next line. Once the parent test
// completes, it will cancel any outstanding subtests.
The timeout option can be used to fail the test if it takes longer than timeout milliseconds to complete. However, it is not a reliable mechanism for
canceling tests because a running test might block the application thread and
thus prevent the scheduled cancellation.
@since ― v18.0.0, v16.17.0
@param ― name The name of the test, which is displayed when reporting test results.
Defaults to the name property of fn, or '<anonymous>' if fn does not have a name.
@param ― options Configuration options for the test.
@param ― fn The function under test. The first argument to this function is a TestContext object.
If the test uses callbacks, the callback function is passed as the second argument.
@return ― Fulfilled with undefined once the test completes, or immediately if the test runs within a suite.
test('2 tokens, then one per second; waits up to 500 ms', async () => {
const
consttime:FakeTimeProvider
time=new
newFakeTimeProvider(start?: number | Date): FakeTimeProvider
A clock you move by hand, so retries, timeouts and open circuits can be tested without waiting.
consttime=newFakeTimeProvider();
constpipeline=newResiliencePipelineBuilder({ timeProvider: time }).addRetry({ delay: '10s' }).addTimeout('1s').build();
// Attach the expectation first: the promise settles while runAll() fires timers.
Polly-style builder with a shortcut for every strategy: addRetry(), addTimeout(), addCircuitBreaker(), …
Convenient, but it bundles every strategy. For the smallest browser bundle use PipelineBuilder with
retryStrategy(), timeoutStrategy(), … instead; the two are interchangeable.
The type parameters track which errors the pipeline can raise, for pipeline.settle() + Outcome.match().
strict.ok(value: unknown, message?: string | Error): asserts value
export strict.ok
Tests if value is truthy. It is equivalent to assert.equal(!!value, true, message).
If value is not truthy, an AssertionError is thrown with a message property set equal to the value of the message parameter. If the message parameter is undefined, a default
error message is assigned. If the message parameter is an instance of an Error then it will be thrown instead of the AssertionError.
If no arguments are passed in at all message will be set to the string:'No value argument passed to `assert.ok()`'.
Be aware that in the repl the error message will be different to the one
thrown in a file! See below for further details.
import assert from'node:assert/strict';
assert.ok(true);
// OK
assert.ok(1);
// OK
assert.ok();
// AssertionError: No value argument passed to `assert.ok()`
assert.ok(false, 'it\'s false');
// AssertionError: it's false
// In the repl:
assert.ok(typeof123==='string');
// AssertionError: false == true
// In a file (e.g. test.js):
assert.ok(typeof123==='string');
// AssertionError: The expression evaluated to a falsy value:
//
// assert.ok(typeof 123 === 'string')
assert.ok(false);
// AssertionError: The expression evaluated to a falsy value:
//
// assert.ok(false)
assert.ok(0);
// AssertionError: The expression evaluated to a falsy value:
//
// assert.ok(0)
import assert from'node:assert/strict';
// Using `assert()` works the same:
assert(0);
// AssertionError: The expression evaluated to a falsy value:
// AssertionError [ERR_ASSERTION]: apples 1 !== oranges 2
assert.strictEqual(1, '1', newTypeError('Inputs are not identical'));
// TypeError: Inputs are not identical
If the values are not strictly equal, an AssertionError is thrown with a message property set equal to the value of the message parameter. If the message parameter is undefined, a
default error message is assigned. If the message parameter is an instance of an Error then it will be thrown
instead of the AssertionError.
@since ― v0.1.21
equal(
constrejected:RateLimiterRejectedError
rejected.
RateLimiterRejectedError.retryAfter: number |undefined
retryAfter, 1000);
// 600 ms later the token is 400 ms away: within queueTimeout, so the call waits for it.
// AssertionError [ERR_ASSERTION]: apples 1 !== oranges 2
assert.strictEqual(1, '1', newTypeError('Inputs are not identical'));
// TypeError: Inputs are not identical
If the values are not strictly equal, an AssertionError is thrown with a message property set equal to the value of the message parameter. If the message parameter is undefined, a
default error message is assigned. If the message parameter is an instance of an Error then it will be thrown
instead of the AssertionError.
Chaos strategies make a pipeline fail on purpose. In a test, set injectionRate: 1 and the failure is certain. Write the
production configuration as a function that receives a builder, then append the chaos strategy last, so it sits where the
real dependency call is and every strategy above it reacts to it:
// Production configuration, shared by the app and the tests.
Polly-style builder with a shortcut for every strategy: addRetry(), addTimeout(), addCircuitBreaker(), …
Convenient, but it bundles every strategy. For the smallest browser bundle use PipelineBuilder with
retryStrategy(), timeoutStrategy(), … instead; the two are interchangeable.
The type parameters track which errors the pipeline can raise, for pipeline.settle() + Outcome.match().
The test() function is the value imported from the test module. Each
invocation of this function results in reporting the test to the TestsStream.
The TestContext object passed to the fn argument can be used to perform
actions related to the current test. Examples include skipping the test, adding
additional diagnostic information, or creating subtests.
test() returns a Promise that fulfills once the test completes.
if test() is called within a suite, it fulfills immediately.
The return value can usually be discarded for top level tests.
However, the return value from subtests should be used to prevent the parent
test from finishing first and cancelling the subtest
as shown in the following example.
test('top level test', async (t) => {
// The setTimeout() in the following subtest would cause it to outlive its
// parent test if 'await' is removed on the next line. Once the parent test
// completes, it will cancel any outstanding subtests.
The timeout option can be used to fail the test if it takes longer than timeout milliseconds to complete. However, it is not a reliable mechanism for
canceling tests because a running test might block the application thread and
thus prevent the scheduled cancellation.
@since ― v18.0.0, v16.17.0
@param ― name The name of the test, which is displayed when reporting test results.
Defaults to the name property of fn, or '<anonymous>' if fn does not have a name.
@param ― options Configuration options for the test.
@param ― fn The function under test. The first argument to this function is a TestContext object.
If the test uses callbacks, the callback function is passed as the second argument.
@return ― Fulfilled with undefined once the test completes, or immediately if the test runs within a suite.
test('serves the fallback when the pricing service is down', async () => {
const
consttime:FakeTimeProvider
time=new
newFakeTimeProvider(start?: number | Date): FakeTimeProvider
A clock you move by hand, so retries, timeouts and open circuits can be tested without waiting.
consttime=newFakeTimeProvider();
constpipeline=newResiliencePipelineBuilder({ timeProvider: time }).addRetry({ delay: '10s' }).addTimeout('1s').build();
// Attach the expectation first: the promise settles while runAll() fires timers.
Polly-style builder with a shortcut for every strategy: addRetry(), addTimeout(), addCircuitBreaker(), …
Convenient, but it bundles every strategy. For the smallest browser bundle use PipelineBuilder with
retryStrategy(), timeoutStrategy(), … instead; the two are interchangeable.
The type parameters track which errors the pipeline can raise, for pipeline.settle() + Outcome.match().
// AssertionError [ERR_ASSERTION]: apples 1 !== oranges 2
assert.strictEqual(1, '1', newTypeError('Inputs are not identical'));
// TypeError: Inputs are not identical
If the values are not strictly equal, an AssertionError is thrown with a message property set equal to the value of the message parameter. If the message parameter is undefined, a
default error message is assigned. If the message parameter is an instance of an Error then it will be thrown
instead of the AssertionError.
// AssertionError [ERR_ASSERTION]: apples 1 !== oranges 2
assert.strictEqual(1, '1', newTypeError('Inputs are not identical'));
// TypeError: Inputs are not identical
If the values are not strictly equal, an AssertionError is thrown with a message property set equal to the value of the message parameter. If the message parameter is undefined, a
default error message is assigned. If the message parameter is an instance of an Error then it will be thrown
instead of the AssertionError.
@since ― v0.1.21
equal(
let reachedDependency:number
reachedDependency, 0); // every attempt was intercepted
});
Use addChaosLatency({ injectionRate: 1, latency: '5s' }) the same way to prove a timeout fires, and
addChaosOutcome({ injectionRate: 1, outcome: Outcome.fromResult(new Response(null, { status: 503 })) }) to fake a response.
For partial failure, keep the rate below 1 and pass a seeded randomizer so the test is repeatable.
setGlobalChaos() also works in tests, but it is one hook for the whole process: call the function it returns in a
finally / afterEach, and don’t use it in tests that run concurrently in the same process.
The test() function is the value imported from the test module. Each
invocation of this function results in reporting the test to the TestsStream.
The TestContext object passed to the fn argument can be used to perform
actions related to the current test. Examples include skipping the test, adding
additional diagnostic information, or creating subtests.
test() returns a Promise that fulfills once the test completes.
if test() is called within a suite, it fulfills immediately.
The return value can usually be discarded for top level tests.
However, the return value from subtests should be used to prevent the parent
test from finishing first and cancelling the subtest
as shown in the following example.
test('top level test', async (t) => {
// The setTimeout() in the following subtest would cause it to outlive its
// parent test if 'await' is removed on the next line. Once the parent test
// completes, it will cancel any outstanding subtests.
The timeout option can be used to fail the test if it takes longer than timeout milliseconds to complete. However, it is not a reliable mechanism for
canceling tests because a running test might block the application thread and
thus prevent the scheduled cancellation.
@since ― v18.0.0, v16.17.0
@param ― name The name of the test, which is displayed when reporting test results.
Defaults to the name property of fn, or '<anonymous>' if fn does not have a name.
@param ― options Configuration options for the test.
@param ― fn The function under test. The first argument to this function is a TestContext object.
If the test uses callbacks, the callback function is passed as the second argument.
@return ― Fulfilled with undefined once the test completes, or immediately if the test runs within a suite.
Polly-style builder with a shortcut for every strategy: addRetry(), addTimeout(), addCircuitBreaker(), …
Convenient, but it bundles every strategy. For the smallest browser bundle use PipelineBuilder with
retryStrategy(), timeoutStrategy(), … instead; the two are interchangeable.
The type parameters track which errors the pipeline can raise, for pipeline.settle() + Outcome.match().
The test() function is the value imported from the test module. Each
invocation of this function results in reporting the test to the TestsStream.
The TestContext object passed to the fn argument can be used to perform
actions related to the current test. Examples include skipping the test, adding
additional diagnostic information, or creating subtests.
test() returns a Promise that fulfills once the test completes.
if test() is called within a suite, it fulfills immediately.
The return value can usually be discarded for top level tests.
However, the return value from subtests should be used to prevent the parent
test from finishing first and cancelling the subtest
as shown in the following example.
test('top level test', async (t) => {
// The setTimeout() in the following subtest would cause it to outlive its
// parent test if 'await' is removed on the next line. Once the parent test
// completes, it will cancel any outstanding subtests.
The timeout option can be used to fail the test if it takes longer than timeout milliseconds to complete. However, it is not a reliable mechanism for
canceling tests because a running test might block the application thread and
thus prevent the scheduled cancellation.
@since ― v18.0.0, v16.17.0
@param ― name The name of the test, which is displayed when reporting test results.
Defaults to the name property of fn, or '<anonymous>' if fn does not have a name.
@param ― options Configuration options for the test.
@param ― fn The function under test. The first argument to this function is a TestContext object.
If the test uses callbacks, the callback function is passed as the second argument.
@return ― Fulfilled with undefined once the test completes, or immediately if the test runs within a suite.
test('emits one OnRetry per retry', async () => {
const
consttime:FakeTimeProvider
time=new
newFakeTimeProvider(start?: number | Date): FakeTimeProvider
A clock you move by hand, so retries, timeouts and open circuits can be tested without waiting.
consttime=newFakeTimeProvider();
constpipeline=newResiliencePipelineBuilder({ timeProvider: time }).addRetry({ delay: '10s' }).addTimeout('1s').build();
// Attach the expectation first: the promise settles while runAll() fires timers.
Polly-style builder with a shortcut for every strategy: addRetry(), addTimeout(), addCircuitBreaker(), …
Convenient, but it bundles every strategy. For the smallest browser bundle use PipelineBuilder with
retryStrategy(), timeoutStrategy(), … instead; the two are interchangeable.
The type parameters track which errors the pipeline can raise, for pipeline.settle() + Outcome.match().
strict.deepEqual<string[]>(actual: unknown, expected: string[], message?: string | Error): asserts actual is string[]
export strict.deepEqual
Tests for deep equality between the actual and expected parameters.
"Deep" equality means that the enumerable "own" properties of child objects
are recursively evaluated also by the following rules.
@since ― v1.2.0
deepEqual(
constevents:string[]
events, [
'OnPipelineExecuting',
'OnExecutionAttempt', 'OnRetry',
'OnExecutionAttempt', 'OnRetry',
'OnExecutionAttempt',
'OnStrategyExecuted', // one per strategy, outermost last
'OnPipelineExecuted',
]);
});
Event args carry the details: OnRetry has attemptNumber, retryDelay and duration; OnCircuitOpened has
breakDuration; OnRateLimiterRejected has retryAfter. The full list is in the events reference.
Strategy order changes behaviour: a timeout added before a retry is a total budget, after it a per-attempt budget.
pipeline.describe() lists the strategies outermost first, so a test can pin the order:
The test() function is the value imported from the test module. Each
invocation of this function results in reporting the test to the TestsStream.
The TestContext object passed to the fn argument can be used to perform
actions related to the current test. Examples include skipping the test, adding
additional diagnostic information, or creating subtests.
test() returns a Promise that fulfills once the test completes.
if test() is called within a suite, it fulfills immediately.
The return value can usually be discarded for top level tests.
However, the return value from subtests should be used to prevent the parent
test from finishing first and cancelling the subtest
as shown in the following example.
test('top level test', async (t) => {
// The setTimeout() in the following subtest would cause it to outlive its
// parent test if 'await' is removed on the next line. Once the parent test
// completes, it will cancel any outstanding subtests.
The timeout option can be used to fail the test if it takes longer than timeout milliseconds to complete. However, it is not a reliable mechanism for
canceling tests because a running test might block the application thread and
thus prevent the scheduled cancellation.
@since ― v18.0.0, v16.17.0
@param ― name The name of the test, which is displayed when reporting test results.
Defaults to the name property of fn, or '<anonymous>' if fn does not have a name.
@param ― options Configuration options for the test.
@param ― fn The function under test. The first argument to this function is a TestContext object.
If the test uses callbacks, the callback function is passed as the second argument.
@return ― Fulfilled with undefined once the test completes, or immediately if the test runs within a suite.
test('payments: retry wraps the breaker and the per-attempt timeout', () => {
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@param ― callbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.
@param ― thisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
strict.deepEqual<string[]>(actual: unknown, expected: string[], message?: string | Error): asserts actual is string[]
export strict.deepEqual
Tests for deep equality between the actual and expected parameters.
"Deep" equality means that the enumerable "own" properties of child objects
are recursively evaluated also by the following rules.
Don’t combine with Jest or Vitest fake timers.FakeTimeProvider yields to the event loop with the real
setTimeout(0). With vi.useFakeTimers() or jest.useFakeTimers() active, that yield never happens and runAll() hangs.
You don’t need both: the pipeline only uses the clock you give it.
Your own timers are real. A callback that does await new Promise((r) => setTimeout(r, 100)) waits 100 real
milliseconds; the fake clock doesn’t know about it. Simulate slowness with chaos latency or a promise you resolve yourself.
runAll() and background loops.circuitHealthCheck, sharedCircuitState and maxRetryAttempts: Infinity schedule
timers forever, so runAll() throws after 10 000 timers. Use advance() for those.
Zero delays have no timer.delay: 0 resolves at once, so pendingTimers doesn’t count it.
Dispose stateful pipelines with background work (pipeline.dispose()) at the end of the test.