wait-for-expect vs poll-until-promise
JavaScript Testing Utilities Comparison
1 Year
wait-for-expectpoll-until-promise
What's JavaScript Testing Utilities?

Both 'poll-until-promise' and 'wait-for-expect' are utility libraries designed to facilitate asynchronous testing in JavaScript. They help developers write tests that wait for certain conditions to be met before proceeding, which is particularly useful in scenarios involving promises or asynchronous operations. These libraries enhance the reliability and readability of tests by allowing developers to express expectations in a more natural manner, ensuring that tests do not fail due to timing issues or race conditions.

Package Weekly Downloads Trend
Github Stars Ranking
Stat Detail
Package
Downloads
Stars
Size
Issues
Publish
License
wait-for-expect581,436296-125 years agoMIT
poll-until-promise7,8811947.9 kB22 years agoISC
Feature Comparison: wait-for-expect vs poll-until-promise

Polling Mechanism

  • wait-for-expect:

    While 'wait-for-expect' does not implement a polling mechanism, it allows assertions to wait for a specific condition to be true before proceeding. This is particularly useful for testing asynchronous code where the timing of state changes is uncertain.

  • poll-until-promise:

    This package provides a simple polling mechanism that repeatedly checks a specified condition until it resolves or a timeout occurs. It allows developers to define a polling interval and a maximum duration, making it flexible for various scenarios where state changes are expected over time.

Integration with Testing Frameworks

  • wait-for-expect:

    'wait-for-expect' is designed to work seamlessly with popular testing frameworks like Jest and Mocha, allowing for a more integrated testing experience. It enhances the readability of tests by allowing expectations to be written in a way that clearly indicates they are waiting for a condition.

  • poll-until-promise:

    This package is a standalone utility and does not have built-in integration with specific testing frameworks. However, it can be easily used in conjunction with any testing framework by wrapping the polling logic in a test case.

Ease of Use

  • wait-for-expect:

    This package offers a very intuitive API that allows developers to write assertions that wait for conditions in a natural way. Its syntax is designed to be familiar to those who are already accustomed to writing tests in Jest or Mocha.

  • poll-until-promise:

    The API is straightforward, requiring minimal setup to start polling for conditions. It is easy to understand and implement, making it suitable for developers who want a quick solution for polling in tests.

Error Handling

  • wait-for-expect:

    'wait-for-expect' handles errors gracefully by allowing assertions to fail if the expected condition is not met within a certain timeframe. This provides clear feedback in test results, making it easier to diagnose issues.

  • poll-until-promise:

    This package provides built-in error handling for timeouts, allowing developers to specify what should happen if the polling does not resolve within the given timeframe. This is crucial for avoiding indefinite waits in tests.

Use Cases

  • wait-for-expect:

    Ideal for writing assertions in tests where you expect an asynchronous operation to eventually yield a certain result, such as waiting for a promise to resolve or for a state change in a component.

  • poll-until-promise:

    Best suited for scenarios where you need to wait for a specific condition to be met, such as waiting for an element to appear in the DOM or for a value to change in an asynchronous operation.

How to Choose: wait-for-expect vs poll-until-promise
  • wait-for-expect:

    Choose 'wait-for-expect' if you prefer a more expressive syntax that integrates seamlessly with popular testing frameworks like Jest and Mocha. It allows you to write expectations that wait for a condition to be true, providing a clearer and more readable way to handle asynchronous assertions.

  • poll-until-promise:

    Choose 'poll-until-promise' if you need a straightforward way to repeatedly check a condition until it resolves or times out. It is particularly useful for polling scenarios where you want to wait for a specific state or value to be achieved, making it ideal for testing asynchronous operations that may take an indeterminate amount of time.

README for wait-for-expect

code style: prettier CircleCI

wait-for-expect

Wait for expectation to be true, useful for integration and end to end testing

Think things like calling external APIs, database operations, or even GraphQL subscriptions. We will add examples for all of them soon, for now please enjoy the simple docs. :-)

Usage:

const waitForExpect = require("wait-for-expect")

test("it waits for the number to change", async () => {
  let numberToChange = 10;
  // we are using random timeout here to simulate a real-time example
  // of an async operation calling a callback at a non-deterministic time
  const randomTimeout = Math.floor(Math.random() * 300);

  setTimeout(() => {
    numberToChange = 100;
  }, randomTimeout);

  await waitForExpect(() => {
    expect(numberToChange).toEqual(100);
  });
});

instead of:


test("it waits for the number to change", () => {
  let numberToChange = 10;
  const randomTimeout = Math.floor(Math.random() * 300);

  setTimeout(() => {
    numberToChange = 100;
  }, randomTimeout);
  
  setTimeout(() => {
    expect(numberToChange).toEqual(100);
  }, 700);
});

It will check whether the expectation passes right away in the next available "tick" (very useful with, for example, integration testing of react when mocking fetches, like here: https://github.com/kentcdodds/react-testing-library#usage).

If it doesn't, it will keep repeating for the duration of, at most, the specified timeout, every 50 ms. The default timeout is 4.5 seconds to fit below the default 5 seconds that Jest waits for before throwing an error.

Nice thing about this simple tool is that if the expectation keeps failing till the timeout, it will check it one last time, but this time the same way your test runner would run it - so you basically get your expectation library error, the sam way like if you used setTimeout to wait but didn't wait long enough.

To show an example - if I change the expectation to wait for 105 in above code, you will get nice and familiar:


 FAIL  src/waitForExpect.spec.js (5.042s)
  ✕ it waits for the number to change (4511ms)

  ● it waits for the number to change

    expect(received).toEqual(expected)
    
    Expected value to equal:
      105
    Received:
      100

       9 |   }, 600);
      10 |   await waitForExpect(() => {
    > 11 |     expect(numberToChange).toEqual(105);
      12 |   });
      13 | });
      14 | 
      
      at waitForExpect (src/waitForExpect.spec.js:11:28)
      at waitUntil.catch (src/index.js:61:5)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   0 total
Time:        5.807s

You can add multiple expectations to wait for, all of them have to pass, and if one of them don't, it will be marked. For example, let's add another expectation for a different number, notice how jest tells you that that's the expectation that failed.

    expect(received).toEqual(expected)
    
    Expected value to equal:
      110
    Received:
      105

      11 |   await waitForExpect(() => {
      12 |     expect(numberToChange).toEqual(100);
    > 13 |     expect(numberThatWontChange).toEqual(110);
      14 |   });
      15 | });
      16 | 
      
      at waitForExpect (src/waitForExpect.spec.js:13:34)
      at waitUntil.catch (src/index.js:61:5)

Since 0.6.0 we can now work with promises, for example, this is now possible:

test("rename todo by typing", async () => {
  // (..)
  const todoToChange = getTodoByText("original todo");
  todoToChange.value = "different text now";
  Simulate.change(todoToChange);

  await waitForExpect(() =>
    expect(
      todoItemsCollection.findOne({
        text: "different text now"
      })).resolves.not.toBeNull()
  );
});

Async Await also works, as in this example - straight from our test case

test("it works with promises", async () => {
  let numberToChange = 10;
  const randomTimeout = Math.floor(Math.random() * 300);

  setTimeout(() => {
    numberToChange = 100;
  }, randomTimeout);

  const sleep = (ms) =>
    new Promise(resolve => setTimeout(() => resolve(), ms));

  await waitForExpect(async () => {
    await sleep(10);
    expect(numberToChange).toEqual(100);
  });
});

(Note: Obviously, in this case it doesn't make sense to put the await sleep there, this is just for demonstration purpose)

API

waitForExpect takes 3 arguments, 2 optional.

/**
 * Waits for predicate to not throw and returns a Promise
 *
 * @param  expectation  Function  Predicate that has to complete without throwing
 * @param  timeout  Number  Maximum wait interval, 4500ms by default
 * @param  interval  Number  Wait interval, 50ms by default
 * @return  Promise  Promise to return a callback result
 */

The defaults for timeout and interval can also be edited globally, e.g. in a jest setup file:

import waitForExpect from 'wait-for-expect';

waitForExpect.defaults.timeout = 2000;
waitForExpect.defaults.interval = 10;

Changelog

1.0.0 - 15 June 2018

( For most people this change doesn't matter. ) Export the function directly in module.exports instead of exporting as an object that has default key. If that's not clear (...it isn't ;-) ) - check #8 #9 . Thanks to @mbaranovski for the PR and @BenBrostoff for creating the issue! I'm making this 1.0.0 as this is breaking for people that currently did:

const { default: waitFor } = require('wait-for-expect');

0.6.0 - 3 May 2018

Work with promises.

0.5.0 - 10 April 2018

Play nicely with jest fake timers (and also in any test tool that overwrites setTimeout) - thanks to @slightlytyler and @kentcoddods for helping to get this resolved.

Credit

Originally based on ideas from https://github.com/devlato/waitUntil. Simplified highly and rewritten for 0.1.0 version. Simplified even more and rewritten even more for 0.2.0 with guidance from Kent C. Dodds: https://github.com/kentcdodds/react-testing-library/pull/25