Version: 27.1

异步示例

首先, 像 Getting Started 里面所说的那样, 启用babel的支持

Let’s implement a module that fetches user data from an API and returns the user name.

user.js

  1. import request from './request';
  2. export function getUserName(userID) {
  3. return request('/users/' + userID).then(user => user.name);
  4. }

In the above implementation, we expect the request.js module to return a promise. We chain a call to then to receive the user name. We chain a call to then to receive the user name.

Now imagine an implementation of request.js that goes to the network and fetches some user data:

request.js

  1. const http = require('http');
  2. export default function request(url) {
  3. return new Promise(resolve => {
  4. // This is an example of an http request, for example to fetch
  5. // user data from an API.
  6. // This module is being mocked in __mocks__/request.js
  7. http.get({path: url}, response => {
  8. let data = '';
  9. response.on('data', _data => (data += _data));
  10. response.on('end', () => resolve(data));
  11. });
  12. });
  13. }

Because we don’t want to go to the network in our test, we are going to create a manual mock for our request.js module in the __mocks__ folder (the folder is case-sensitive, __MOCKS__ will not work). 就像是这样: 就像是这样:

__mocks__/request.js

  1. const users = {
  2. 4: {name: 'Mark'},
  3. 5: {name: 'Paul'},
  4. };
  5. export default function request(url) {
  6. return new Promise((resolve, reject) => {
  7. const userID = parseInt(url.substr('/users/'.length), 10);
  8. process.nextTick(() =>
  9. users[userID]
  10. ? resolve(users[userID])
  11. : reject({
  12. error: 'User with ' + userID + ' not found.',
  13. }),
  14. );
  15. });
  16. }

现在我们就来编写我们的异步函数的测试

__tests__/user-test.js

  1. jest.mock('../request');
  2. import * as user from '../user';
  3. // The assertion for a promise must be returned.
  4. it('works with promises', () => {
  5. expect.assertions(1);
  6. return user.getUserName(4).then(data => expect(data).toEqual('Mark'));
  7. });

我们调用 jest.mock('../request ') 告诉jest 使用我们手动的创建的模拟数据。 通过 resolves能更加简单地解析一个fulfilled 态的 Promise的返回值. 如果Promise是rejected态的话, 断言将会返回失败. it 断言的是将会返回一个Promise对象. You can chain as many Promises as you like and call expect at any time, as long as you return a Promise at the end.

.resolves

There is a less verbose way using resolves to unwrap the value of a fulfilled promise together with any other matcher. If the promise is rejected, the assertion will fail.

  1. it('works with resolves', () => {
  2. expect.assertions(1);
  3. return expect(user.getUserName(5)).resolves.toEqual('Paul');
  4. });

async/await

Writing tests using the async/await syntax is also possible. Here is how you’d write the same examples from before: Here is how you’d write the same examples from before:

  1. // 使用async/await
  2. // 使用async/await
  3. it('works with async/await', async () => {
  4. expect.assertions(1);
  5. const data = await user.getUserName(4);
  6. expect(data).toEqual('Mark');
  7. });
  8. // async/await 也可以和 `.resolves` 一起使用.
  9. it('works with async/await and resolves', async () => {
  10. expect.assertions(1);
  11. await expect(user.getUserName(5)).resolves.toEqual('Paul');
  12. });
  13. it('works with async/await and resolves', async () => {
  14. expect.assertions(1);
  15. await expect(user.getUserName(5)).resolves.toEqual('Paul');
  16. });

To enable async/await in your project, install @babel/preset-env and enable the feature in your babel.config.js file.

错误处理

可以使用 .catch 方法处理错误。 请确保添加 expect.assertions 来验证一定数量的断言被调用。 否则一个fulfilled态的Promise 不会让测试失败︰

  1. //用 Promise.catch 测试一个异步的错误
  2. //用 Promise.catch 测试一个异步的错误
  3. it('tests error with promises', () => {
  4. expect.assertions(1);
  5. return user.getUserName(2).catch(e =>
  6. expect(e).toEqual({
  7. error: 'User with 2 not found.',
  8. }),
  9. );
  10. });
  11. // Or using async/await.
  12. it('tests error with async/await', async () => {
  13. expect.assertions(1);
  14. try {
  15. await user.getUserName(1);
  16. } catch (e) {
  17. expect(e).toEqual({
  18. error: 'User with 1 not found.',
  19. });
  20. }
  21. });
  22. it('tests error with async/await', async () => {
  23. expect.assertions(1);
  24. try {
  25. await user.getUserName(1);
  26. } catch (e) {
  27. expect(e).toEqual({
  28. error: 'User with 1 not found.',
  29. });
  30. }
  31. });

.rejects

The.rejects helper works like the .resolves helper. 如果 Promise 被拒绝,则测试将自动失败。 如果 Promise 被拒绝,则测试将自动失败。 expect.assertions(number) is not required but recommended to verify that a certain number of assertions are called during a test. It is otherwise easy to forget to return/await the .resolves assertions.

  1. // 用`.rejects`.来测试一个异步的错误
  2. // 用`.rejects`.来测试一个异步的错误
  3. it('tests error with rejects', () => {
  4. expect.assertions(1);
  5. return expect(user.getUserName(3)).rejects.toEqual({
  6. error: 'User with 3 not found.',
  7. });
  8. });
  9. // 或者与async/await 一起使用 `.rejects`.
  10. it('tests error with async/await and rejects', async () => {
  11. expect.assertions(1);
  12. await expect(user.getUserName(3)).rejects.toEqual({
  13. error: 'User with 3 not found.',
  14. });
  15. });
  16. it('tests error with async/await and rejects', async () => {
  17. expect.assertions(1);
  18. await expect(user.getUserName(3)).rejects.toEqual({
  19. error: 'User with 3 not found.',
  20. });
  21. });

The code for this example is available at examples/async.

If you’d like to test timers, like setTimeout, take a look at the Timer mocks documentation.