persevere-js
TypeScript icon, indicating that this package has built-in type declarations

1.5.0 • Public • Published

Welcome to PersevereJS 👋

Build Version Documentation Maintenance Licence Zero Runtime Dependencies

Description

A small utility that provides an easy-to-read syntax for awaiting on a condition to be satisfied. This makes testing asynchronous logic a breeze!

Heavily inspired by Awaitility which is a Java utility aimed at testing asynchronous systems.

Example

This utility could be used in both production and test code, but primarily use cases tend towards the latter.

For this example, imagine a simple backend for a local book store. The developer of the system wants to check the asynchronous 'real time' stocking system, which utilises a message queue. The flow for this is as follows:

  1. Customer purchases a book
  2. Purchase is placed onto a messaging queue for asynchronous processing
  3. The message is consumed at some point later (usually milliseconds, sometimes seconds, but never more than 10 seconds) later by the bookstore backend
  4. The books quantity is decremented by 1 in the database

The developer sets up the following simple test for this, thanks to PersevereJS 🚀

import { persevereFor } from "persevere-js";

describe('Stocking Tests', () => {
    it('should decrement stock quantity, when a book is purchased', async () => {
        // Given
        const book = new Book('Harry Potter and the Philosophers Stone')
        
        // When
        bookService.addPurchaseToQueue(book)
        
        // Then
        await persevereFor().atMost(10, 'SECONDS').until(() => bookRepository.getStockCountFor(book)).yieldsValue(0)
    })
})

In the above example, one of two things will happen:

  1. The stock count will become 0 for the book within the allotted 10-second period.
  2. The purchase message is never consumer, or takes longer than 10 seconds to be delivered and an exception will be thrown.

Usage

By chaining temporal bindings and until conditions, you can craft powerful mechanisms to wait for asynchronous conditions to satisfy.

The entrypoint into the wonderful world of waiting is the persevereFor function (note: persevere is also available and is functionally identical).

// Wait for at most 30 seconds, for there to be an order from bob in the databsse
await persevereFor()
    .atMost(30, 'SECONDS')
    .until(async () => {
        return db.query('SELECT ORDER_ID, CUSTOMER_ID FROM CUSTOMER_ORDERS');
    })
    .satisfies((customerOrders: { orderId: string, customerId: string}[]) => {
        return customerOrders
            .find(order => order.customerId = 'bob') != undefined;
    })

Temporal Bindings

You can utilise the following temporal bindings for your persevere functions:

  • atMost - Wait for at most the specified time for the condition to be met.
  • atLeast - Expect that at least the specified time has passed before the condition is met. (Note: Must also provide an upper temporal bound).

Until Conditions

You can utilise the following until conditions for determining success

  • yieldsValue - Stop waiting once the underlying promissory function yields the value specified.
  • satisfies - Stop waiting once the underlying promissory function satisfies the provided predicate.
  • noExceptions - Stop waiting as soon as the underlying promissory function resolves (doesn't reject/throw).

Licence

Copyright (c) 2023 James McNee Licensed under the MIT license.


This README was generated with ❤️ by readme-md-generator

Package Sidebar

Install

npm i persevere-js

Weekly Downloads

399

Version

1.5.0

License

MIT

Unpacked Size

44 kB

Total Files

26

Last publish

Collaborators

  • james-mcnee