Files
jest/docs/TestingAsyncCode.md
T
Eric NakagawaandGitHub dc4f67a99b Update website to use Docusaurus (#4536)
* Adding a clean copy of Docusaurus

Updating sidebar

Modifying files into Docusaurus format

Slight header logo CSS change

Ignore translated files and build directory

Proper file locations for Docusaurus

Move blog files to Docusaurus preferred location, modified crowdin to output /docs to /translated_pages, updated siteConfig.js

Eslinting Docusaurus files

Ignoring website/blog pages

Linter fixes

* Updating Circle config to remove website test

* Updating Circle config to auto-deploy website

* Add @deltice's config changes before website build, skip yarn build step

* Switch crowdin branch to master

* Updating siteconfig to @deltice's file

* Test crowdin branch

* Switching Crowdin to master

* Uses yarn to install, run, and deploy

* Feedback fixes

Switch to use process.env.VAR for algolia key

Switching crowdin upload/download to use yarn

Circle CI fix

Adding a delay to crowdin

Fixing prettier errors

Updating crowdin command in circle ci config

Path fix

* Upgrading docusaurus to 1.0.0a40, adds an RSS/Atom feed

* Update Docusaurus version

* Updated footer to reflect current footer. Updated footer logo.

* Fixes Edit this doc link, removes node_modules from .gitignore

* Move .gitignore rules to top level

* Updating license file in siteConfig to MIT, added new Docusaurus beta to package.json

* Lint fix

* Editing siteConfig.js to account for /docs not living in /docs/en
2017-10-11 09:00:06 +01:00

4.6 KiB

id, title
id title
asynchronous Testing Asynchronous Code

It's common in JavaScript for code to run asynchronously. When you have code that runs asynchronously, Jest needs to know when the code it is testing has completed, before it can move on to another test. Jest has several ways to handle this.

Callbacks

The most common asynchronous pattern is callbacks.

For example, let's say that you have a fetchData(callback) function that fetches some data and calls callback(data) when it is complete. You want to test that this returned data is just the string 'peanut butter'.

By default, Jest tests complete once they reach the end of their execution. That means this test will not work as intended:

// Don't do this!
test('the data is peanut butter', () => {
  function callback(data) {
    expect(data).toBe('peanut butter');
  }

  fetchData(callback);
});

The problem is that the test will complete as soon as fetchData completes, before ever calling the callback.

There is an alternate form of test that fixes this. Instead of putting the test in a function with an empty argument, use a single argument called done. Jest will wait until the done callback is called before finishing the test.

test('the data is peanut butter', done => {
  function callback(data) {
    expect(data).toBe('peanut butter');
    done();
  }

  fetchData(callback);
});

If done() is never called, the test will fail, which is what you want to happen.

Promises

If your code uses promises, there is a simpler way to handle asynchronous tests. Just return a promise from your test, and Jest will wait for that promise to resolve. If the promise is rejected, the test will automatically fail.

For example, let's say that fetchData, instead of using a callback, returns a promise that is supposed to resolve to the string 'peanut butter'. We could test it with:

test('the data is peanut butter', () => {
  expect.assertions(1);
  return fetchData().then(data => {
    expect(data).toBe('peanut butter');
  });
});

Be sure to return the promise - if you omit this return statement, your test will complete before fetchData completes.

If you expect a promise to be rejected use the .catch method. Make sure to add expect.assertions to verify that a certain number of assertions are called. Otherwise a fulfilled promise would not fail the test.

test('the fetch fails with an error', () => {
  expect.assertions(1);
  return fetchData().catch(e =>
    expect(e).toMatch('error')
  );
});

.resolves / .rejects

available in Jest 20.0.0+

You can also use the .resolves matcher in your expect statement, and Jest will wait for that promise to resolve. If the promise is rejected, the test will automatically fail.

test('the data is peanut butter', () => {
  expect.assertions(1);
  return expect(fetchData()).resolves.toBe('peanut butter');
});

Be sure to return the assertion—if you omit this return statement, your test will complete before fetchData completes.

If you expect a promise to be rejected use the .rejects matcher. It works analogically to the .resolves matcher. If the promise is fulfilled, the test will automatically fail.

test('the fetch fails with an error', () => {
  expect.assertions(1);
  return expect(fetchData()).rejects.toMatch('error');
});

Async/Await

Alternatively, you can use async and await in your tests. To write an async test, just use the async keyword in front of the function passed to test. For example, the same fetchData scenario can be tested with:

test('the data is peanut butter', async () => {
  expect.assertions(1);
  const data = await fetchData();
  expect(data).toBe('peanut butter');
});

test('the fetch fails with an error', async () => {
  expect.assertions(1);
  try {
    await fetchData();
  } catch (e) {
    expect(e).toMatch('error');
  }
});

Of course, you can combine async and await with .resolves or .rejects (available in Jest 20.0.0+).

test('the data is peanut butter', async () => {
  expect.assertions(1);
  await expect(fetchData()).resolves.toBe('peanut butter');
});

test('the fetch fails with an error', async () => {
  expect.assertions(1);
  await expect(fetchData()).rejects.toMatch('error');
});

In these cases, async and await are effectively just syntactic sugar for the same logic as the promises example uses.

None of these forms is particularly superior to the others, and you can mix and match them across a codebase or even in a single file. It just depends on which style makes your tests simpler.