Jest проверка на ошибку

Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Тестирование ошибок

JS: Продвинутое тестирование

Основные тесты, которые нужно писать, это тесты на успешные сценарии работы. Но в некоторых ситуациях код должен возвращать ошибки и их тоже бывает нужно проверять. Под ошибками понимаются ситуации, в которых код выбрасывает исключение. В чем их особенность? Посмотрите на тест:

test('boom!', () => {
  try {
    functionWithException(0);
  } catch (e) {
    expect(e).not.toBeNull();
  }
});

Этот код пытается протестировать ситуацию, при которой функция functionWithException() выбрасывает исключение, если ей передать 0. Как вы думаете, этот тест проверит, что функция действительно порождает исключение?

Правильный ответ — нет. Если функция functionWithException() не выбросит исключение, то тест пройдет, так как код не попадет в блок catch.

Документация Jest предлагает свой способ тестирования таких ситуаций. Jest позволяет указать количество утверждений, которые должны выполниться в тесте. Если этого не происходит, то Jest сообщает об ошибке:

test('boom!', () => {
  // Количество утверждений, которые должны быть запущены в этом тесте
  expect.assertions(1);

  try {
    functionWithException(0);
  } catch (e) {
    expect(e).not.toBeNull();
  }
});

Этот способ крайне опасен. Он порождает хрупкие тесты, которые завязаны на то, как они написаны. Если вы захотите добавить новое утверждение, то тест провалится и придется его править. Вам всегда придется следить за тем, чтобы это число было правильным. Не используйте этот подход, чем больше контекстной зависимости, тем сложнее разобраться в коде и проще наделать ошибок.

И наконец-то мы подобрались к правильному способу. В Jest есть матчер, который самостоятельно отлавливает исключение и проверяет, что оно вообще было сгенерировано.

test('boom!', () => {
  expect(() => {
    functionWithException(0);
  }).toThrow();
});

Главная особенность этого матчера в том, что он принимает на вход функцию, которая вызывается внутри. Благодаря этому, он может самостоятельно отследить появление исключения. Этот код не содержит неявного состояния и лишних проверок, он делает ровно то, что нужно делать и не требует от нас слишком много. Более того, теоретически возможен тест, в котором делается сразу несколько проверок на различные исключения. Это значительно сложнее провернуть с предыдущими способами.

Иногда важно не просто поймать исключение, но и убедиться в том, что это ожидаемое исключение. Сделать это можно, передав в матчер toThrow() строку, которая должна присутствовать в сообщении исключения.

test('boom!', () => {
  expect(() => {
    functionWithException(0);

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно


  • 130 курсов, 2000+ часов теории

  • 1000 практических заданий в браузере

  • 360 000 студентов

Наши выпускники работают в компаниях:

Рекомендуемые программы

профессия


от 6 300 ₽ в месяц

Разработка фронтенд-компонентов для веб-приложений

профессия


от 6 300 ₽ в месяц

Разработка бэкенд-компонентов для веб-приложений

профессия


от 10 080 ₽ в месяц

Разработка фронтенд- и бэкенд-компонентов для веб-приложений

профессия


от 6 300 ₽ в месяц

Автоматизированное тестирование веб-приложений на JavaScript

в разработке

дата определяется

In Jest you have to pass a function into expect(function).toThrow(<blank or type of error>).

Example:

test("Test description", () => {
  const t = () => {
    throw new TypeError();
  };
  expect(t).toThrow(TypeError);
});

Or if you also want to check for error message:

test("Test description", () => {
  const t = () => {
    throw new TypeError("UNKNOWN ERROR");
  };
  expect(t).toThrow(TypeError);
  expect(t).toThrow("UNKNOWN ERROR");
});

If you need to test an existing function whether it throws with a set of arguments, you have to wrap it inside an anonymous function in expect().

Example:

test("Test description", () => {
  expect(() => {http.get(yourUrl, yourCallbackFn)}).toThrow(TypeError);
});

answered Sep 11, 2017 at 12:06

PeterDanis's user avatar

PeterDanisPeterDanis

7,8502 gold badges12 silver badges23 bronze badges

10

It is a little bit weird, but it works and IMHO is good readable:

it('should throw Error with message 'UNKNOWN ERROR' when no parameters were passed', () => {
  try {
      throwError();
      // Fail test if above expression doesn't throw anything.
      expect(true).toBe(false);
  } catch (e) {
      expect(e.message).toBe("UNKNOWN ERROR");
  }
});

The Catch block catches your exception, and then you can test on your raised Error. Strange expect(true).toBe(false); is needed to fail your test if the expected Error will be not thrown. Otherwise, this line is never reachable (Error should be raised before them).

@Kenny Body suggested a better solution which improve a code quality if you use expect.assertions():

it('should throw Error with message 'UNKNOWN ERROR' when no parameters were passed', () => {
  expect.assertions(1);
  try {
      throwError();
  } catch (e) {
      expect(e.message).toBe("UNKNOWN ERROR");
  }
});

See the original answer with more explanations: How to test the type of a thrown exception in Jest

EDIT 2022:

To use this approach and not trigger no-conditional-expect rule (if you’re using eslint-plugin-jest), documentation of this rule suggest to use error wrapper:

class NoErrorThrownError extends Error {}

const getError = async <TError>(call: () => unknown): Promise<TError> => {
  try {
    await call();

    throw new NoErrorThrownError();
  } catch (error: unknown) {
    return error as TError;
  }
};

describe('when the http request fails', () => {
  it('includes the status code in the error', async () => {
    const error = await getError(async () => makeRequest(url));

    // check that the returned error wasn't that no error was thrown
    expect(error).not.toBeInstanceOf(NoErrorThrownError);
    expect(error).toHaveProperty('statusCode', 404);
  });
});

See: no-conditional-expect docs

answered Mar 27, 2018 at 12:31

Paweł BB Drozd's user avatar

Paweł BB DrozdPaweł BB Drozd

4,4034 gold badges21 silver badges17 bronze badges

10

I use a slightly more concise version:

expect(() => {
  // Code block that should throw error
}).toThrow(TypeError) // Or .toThrow('expectedErrorMessage')

Peter Mortensen's user avatar

answered May 23, 2019 at 8:46

Tal Joffe's user avatar

Tal JoffeTal Joffe

5,2774 gold badges25 silver badges31 bronze badges

0

From my (albeit limited) exposure to Jest, I have found that expect().toThrow() is suitable if you want to only test an error is thrown of a specific type:

expect(() => functionUnderTest()).toThrow(TypeError);

Or an error is thrown with a specific message:

expect(() => functionUnderTest()).toThrow('Something bad happened!');

If you try to do both, you will get a false positive. For example, if your code throws RangeError('Something bad happened!'), this test will pass:

expect(() => functionUnderTest()).toThrow(new TypeError('Something bad happened!'));

The answer by bodolsog which suggests using a try/catch is close, but rather than expecting true to be false to ensure the expect assertions in the catch are hit, you can instead use expect.assertions(2) at the start of your test where 2 is the number of expected assertions. I feel this more accurately describes the intention of the test.

A full example of testing the type and message of an error:

describe('functionUnderTest', () => {
    it('should throw a specific type of error.', () => {
        expect.assertions(2);

        try {
            functionUnderTest();
        } catch (error) {
            expect(error).toBeInstanceOf(TypeError);
            expect(error).toHaveProperty('message', 'Something bad happened!');
        }
    });
});

If functionUnderTest() does not throw an error, the assertions will be be hit, but the expect.assertions(2) will fail and the test will fail.

Peter Mortensen's user avatar

answered Sep 25, 2019 at 17:27

Kenny Body's user avatar

Kenny BodyKenny Body

1,0198 silver badges5 bronze badges

5

I manage to combine some answers and end up with this:

it('should throw', async () => {
    await expect(service.methodName('some@email.com', 'unknown')).rejects.toThrow(
      HttpException,
    );
  });

answered Jul 28, 2021 at 8:37

Douglas Caina's user avatar

2

Modern Jest allows you to make more checks on a rejected value. For example, you could test status code of http exception:

const request = Promise.reject({statusCode: 404})
await expect(request).rejects.toMatchObject({ statusCode: 500 });

will fail with error

Error: expect(received).rejects.toMatchObject(expected)

- Expected
+ Received

  Object {
-   "statusCode": 500,
+   "statusCode": 404,
  }

answered Oct 10, 2019 at 15:50

Slava Baginov's user avatar

Slava BaginovSlava Baginov

9191 gold badge8 silver badges10 bronze badges

2

Further to Peter Danis’ post, I just wanted to emphasize the part of his solution involving «[passing] a function into expect(function).toThrow(blank or type of error)».

In Jest, when you test for a case where an error should be thrown, within your expect() wrapping of the function under testing, you need to provide one additional arrow function wrapping layer in order for it to work. I.e.

Wrong (but most people’s logical approach):

expect(functionUnderTesting();).toThrow(ErrorTypeOrErrorMessage);

Right:

expect(() => { functionUnderTesting(); }).toThrow(ErrorTypeOrErrorMessage);

It’s very strange, but it should make the testing run successfully.

Peter Mortensen's user avatar

answered May 24, 2020 at 7:05

Adrian's user avatar

AdrianAdrian

1,60510 silver badges6 bronze badges

3

In case you are working with Promises:

await expect(Promise.reject(new HttpException('Error message', 402)))
  .rejects.toThrowError(HttpException);

answered Jan 28, 2020 at 22:30

Željko Šević's user avatar

Željko ŠevićŽeljko Šević

3,6662 gold badges25 silver badges23 bronze badges

2

You must wrap the code of the function that you are expecting in another arrow function, otherwise the error will not be caught and the assertion will fail.

the function you want to test :

const testThrowingError = () => {
    throw new Error();
  };

the test:

describe("error function should Throw Error", () => {
  expect(() =>testThrowingError()).toThrowError();
});

resource:
https://jestjs.io/docs/expect#tothrowerror

answered Jul 4, 2022 at 13:50

Safi Habhab's user avatar

Safi HabhabSafi Habhab

96110 silver badges17 bronze badges

Check out toThrow method.

You must wrap the code in an additional function callback!

You should check both: the error message and its type.

For example:

// additional function wrap
const wrap = () => {
  yourCodeToTest();
};

// test error message
expect(wrap).toThrow('UNKNOWN ERROR');

// test error type
expect(wrap).toThrow(TypeError);

Because of additional callback wrap, the code will not be run immediately, so jest will be able to catch it.

You should always check the error message to be sure you are checking the correct throw case and not getting another error your code may throw.

It is also nice to check the error type, so the client code may rely on it.

answered May 10, 2021 at 3:48

Igor Sukharev's user avatar

1

There’s a way to wait an error that comes from a async function, you just have to write your code like in the example bellow

await expect(yourAsyncFunction()).rejects.toThrowError();

answered Jul 7, 2022 at 18:53

Hiran Júnior's user avatar

I haven’t tried it myself, but I would suggest using Jest’s toThrow assertion. So I guess your example would look something like this:

it('should throw Error with message 'UNKNOWN ERROR' when no parameters were passed', (t) => {
  const error = t.throws(() => {
    throwError();
  }, TypeError);

  expect(t).toThrowError('UNKNOWN ERROR');
  //or
  expect(t).toThrowError(TypeError);
});

Again, I haven’t test it, but I think it should work.

Peter Mortensen's user avatar

answered Sep 4, 2017 at 18:48

Andrei CACIO's user avatar

Andrei CACIOAndrei CACIO

2,09114 silver badges28 bronze badges

I have successfully used this

await expect(
      async () => await apiCalls()
    ).rejects.toThrow();

answered Feb 28, 2022 at 20:00

Liu Hantao's user avatar

Liu HantaoLiu Hantao

6101 gold badge9 silver badges19 bronze badges

Jest has a method, toThrow(error), to test that a function throws when it is called.

So, in your case you should call it so:

expect(t).toThrowError(TypeError);

The documentation.

Peter Mortensen's user avatar

answered Sep 4, 2017 at 18:49

alexmac's user avatar

alexmacalexmac

18.9k7 gold badges57 silver badges68 bronze badges

1

The documentation is clear on how to do this. Let’s say I have a function that takes two parameters and it will throw an error if one of them is null.

function concatStr(str1, str2) {
  const isStr1 = str1 === null
  const isStr2 = str2 === null
  if(isStr1 || isStr2) {
    throw "Parameters can't be null"
  }
  ... // Continue your code

Your test

describe("errors", () => {
  it("should error if any is null", () => {
    // Notice that the expect has a function that returns the function under test
    expect(() => concatStr(null, "test")).toThrow()
  })
})

Peter Mortensen's user avatar

answered Dec 14, 2019 at 15:12

redeemefy's user avatar

redeemefyredeemefy

4,4916 gold badges36 silver badges50 bronze badges

I ended up writing a convenience method for our test-utils library

/**
 *  Utility method to test for a specific error class and message in Jest
 * @param {fn, expectedErrorClass, expectedErrorMessage }
 * @example   failTest({
      fn: () => {
        return new MyObject({
          param: 'stuff'
        })
      },
      expectedErrorClass: MyError,
      expectedErrorMessage: 'stuff not yet implemented'
    })
 */
  failTest: ({ fn, expectedErrorClass, expectedErrorMessage }) => {
    try {
      fn()
      expect(true).toBeFalsy()
    } catch (err) {
      let isExpectedErr = err instanceof expectedErrorClass
      expect(isExpectedErr).toBeTruthy()
      expect(err.message).toBe(expectedErrorMessage)
    }
  }

answered Jun 20, 2019 at 8:31

kpollock's user avatar

kpollockkpollock

3,8798 gold badges42 silver badges61 bronze badges

2

There is also an easier way to assert against the error message. The beauty of this method is that you don’t need to reconstruct the error object or have the full error message. As long as your error contains part of the error message we can assume it is of the correct type. i.e

 const printOnlyString = (str) => {
   if(typeof str !== "string"){
     throw Error("I can only print strings ${typeof str) given");
   }
   else {
     console.log(str);
   } 
 }

expect(() => printOnlyString(123)).toThrow(/can only print strings/)

answered Oct 21, 2022 at 16:08

Yasin Yaqoobi's user avatar

Yasin YaqoobiYasin Yaqoobi

1,8783 gold badges27 silver badges37 bronze badges

1

To test whether a function throws a specific error message with a specific type of error, you can use Jest’s toThrow() matcher

function myFunction() {
  throw new TypeError('Something went wrong');
}

describe('myFunction', () => {
  it('should throw a TypeError with a specific error message', () => {
    expect(myFunction).toThrow(TypeError);
    expect(myFunction).toThrow(/Something went wrong/);

    //noted: this way will invoke the myFunction twice
    expect(myFunction).toBeCalledTimes(2)
  });
});

If you use expect(myFunction).toThrow(new TypeError("Something went wrong"), it only checks the error message rather than the error type, which does not meet the test purpose.

answered Apr 28 at 2:45

Kaiwen Luo's user avatar

Kaiwen LuoKaiwen Luo

3503 silver badges9 bronze badges

A good way is to create custom error classes and mock them. Then you can assert whatever you want.

MessedUpError.ts

type SomeCrazyErrorObject = {
  [key: string]: unknown,
}

class MessedUpError extends Error {
  private customErrorData: SomeCrazyErrorObject = {};

  constructor(err?: string, data?: SomeCrazyErrorObject) {
    super(err || 'You messed up');

    Object.entries(data ?? {}).forEach(([Key, value]) => {
      this.customErrorData[Key] = value;
    });
    Error.captureStackTrace(this, this.constructor);
  }

  logMe() {
    console.log(this.customErrorData);
  }
}

export default MessedUpError;

messedUpError.test.ts

import MessedUpError from './MessedUpError';

jest.mock('./MessedUpError', () => jest.fn().mockImplementation((...args: any[]) => ({
  constructor: args,
  log: () => {},
})));

type MessedUpErrorContructorParams = Expand<typeof MessedUpError['prototype']>
const MessedUpErrorMock = MessedUpError as unknown as jest.Mock<MessedUpError, [MessedUpErrorContructorParams]>;

const serverErrorContructorCall = (i = 0) => ({
  message: MessedUpErrorMock.mock.calls[i][0],
  ...MessedUpErrorMock.mock.calls[i][1] || {},
});

beforeEach(() => {
  MessedUpErrorMock.mockClear();
});

test('Should throw', async () => {
  try {
    await someFunctionThatShouldThrowMessedUpError();
  } catch {} finally {
    expect(MessedUpErrorMock).toHaveBeenCalledTimes(1);
    const constructorParams = serverErrorContructorCall();
    expect(constructorParams).toHaveProperty('message', 'You messed up');
    expect(constructorParams).toHaveProperty('customErrorProperty', 'someValue');
  }
});

The assertions always go inside the finally clause. This way it will always be asserted. Even if the test does not throw any errors.

answered Apr 1, 2022 at 13:49

Omar Omeiri's user avatar

Omar OmeiriOmar Omeiri

1,4381 gold badge17 silver badges31 bronze badges

Try:

expect(t).rejects.toThrow()

Peter Mortensen's user avatar

answered May 16, 2019 at 16:37

Razim Saidov's user avatar

2

Agenda

  1. The goal of this post
  2. expect.assertions(number) rather than done()
  3. .rejects rather than try-catch
  4. .toThrow rather than toMatch or toEqual
  5. Use-case 1: Handle Error in a function
  6. Use-case 2: Handle Error in an asynchronous function
  7. References

1. The goal of this post

The goal of this post is to give you an opinionated way of how to handle error with jest. Since a bunch of source, including the official guide, suggests various ways (but each way has its own rule to comply with 😡), it would mislead to testing.

2. expect.assertions(number) rather than done()

Both expect.assertions() and done() are used to test async functions. However, expect.assertions() is focused on to verify that a certain number of assertions are called during a test while done() is focused on to wait a certain assertion to be called. Therefore, expect.assertions() would fail if the number of expectations are not called while done() would fail because of timeout (mostly from not calling done() at the end).

Let’s compare between done() and expect.assertion(number) when doing async calls.

API — expect.assertions(number)

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('doAsync calls both callbacks', () => {
  expect.assertions(2);
  function callback1(data) {
    expect(data).toBeTruthy();
  }
  function callback2(data) {
    expect(data).toBeTruthy();
  }

  doAsync(callback1, callback2);
});

Enter fullscreen mode

Exit fullscreen mode

VS.

Testing Asynchronous Code — callbacks

done() is necessary. Otherwise, the test will complete as soon as fetchData completes, before ever calling the callback.

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

  fetchData(callback);
});

Enter fullscreen mode

Exit fullscreen mode

You could notice at a glance that done(error) is declared in the catch block in order to avoid timeout. On the one hand, you could easily notice errors and reduce your time to figure out what went wrong by doing so. On the other hand, you could easily forget that where you need to declare done() properly.

The rule of thumbs here is to declare expect.assertions(number) at the beginning of your tests. It never causes a problem at all.

3. .rejects rather than try-catch

API — .rejects

Use .rejects to unwrap the reason of a rejected promise so any other matcher can be chained. If the promise is fulfilled the assertion fails.

test('rejects to octopus', async () => {
  await expect(Promise.reject(new Error('octopus'))).rejects.toThrow('octopus');
});

Enter fullscreen mode

Exit fullscreen mode

VS.

Stack Overflow

You must handle errors at the catch block.

it('calls the API and throws an error', async () => {
  expect.assertions(2);
  try {
    await login('email', 'password');
  } catch (error) {
    expect(error.name).toEqual('Unauthorized');
    expect(error.status).toEqual(401);
  }
});

Enter fullscreen mode

Exit fullscreen mode

You know the test is supposed to cause an error. The key point of .rejects() is that the assertion fails when the promise is fulfilled.

!CAUTION
Be sure to return (or await) the promise — if you omit the return/await statement, your test will complete before the promise returned from fetchData resolves or rejects.

!tip
expect.assertions(number) while using .rejects is not required but recommended to verify that a certain number of assertions are called during a test.

4. .toThrow rather than toMatch or toEqual

You can provide an optional argument to test that a specific error is thrown such as regex, string, error object, and error class. However, toMatch and toEqual only do one thing each: to match a string and equal to an object.

API — .toThrow

test('throws on octopus', () => {
  expect(() => {
    drinkFlavor('octopus');
  }).toThrow();
});

Enter fullscreen mode

Exit fullscreen mode

Stack Overflow

test("Test description", () => {
  const t = () => {
    throw new TypeError("UNKNOWN ERROR");
  };
  expect(t).toThrow(TypeError);
  expect(t).toThrow("UNKNOWN ERROR");
});

Enter fullscreen mode

Exit fullscreen mode

!tip
You must wrap the code in a function, otherwise the error will not be caught and the assertion will fail.

!tip
You don’t need to wrap a promise function. Just invoke it.
Code Example

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

Enter fullscreen mode

Exit fullscreen mode

5. Use-case 1: Handle Error in a function

Let’s integrate what we learned into a simple code snippet.

test("Test description", () => {
  expect.assertions(2);
  const t = () => {
    throw new TypeError("UNKNOWN ERROR");
  };
  expect(t).toThrow(TypeError);
  expect(t).toThrow("UNKNOWN ERROR");
});

Enter fullscreen mode

Exit fullscreen mode

  • I declared expect.assertions(number) even though the above test is not asynchronous. It doesn’t matter since expect.assertions() never causes a problem at all.
  • I used .toThrow() rather than .toMatch or .toEqual since it handles Error object and string alike.

6. Use-case 2: Handle Error in an asynchronous function

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

Enter fullscreen mode

Exit fullscreen mode

  • I declared expect.assertions(number) even though it is not required while using .rejects().
  • I handled an error, by using .rejects, within a single block, not within a try-catch block.
  • I used .toThrow rather than .toMatch or .toEqual.

7. References

  • Jest API — expect
  • Jest Guide — An Async Example
  • Jest Introduction — Testing Asynchronous Code
  • How to test the type of a thrown exception in Jest
  • Necessary to use expect.assertions() if you’re awaiting any async function calls?
  • Can you write async tests that expect toThrow?
  • Writing Good Assertions

Whenever you are looking to test an error thrown by a function in Jest, you want to pass the function to the expect, rather than invoking the function. Take a look at the following examples:

const functionWithError = param => {  
    throw new Error()
}

it('should throw an error', () => {
    expect(functionWithError).toThrow(Error)
})

Copied to clipboard!

We have a mock function and we want to test whether it throws the error we are expecting. We can do this by simply passing the function to the expect without actually invoking it, and calling the toThrow method on it with the passed error.

But what if you have to call the function, for example, to provide parameters? In this case, you can wrap the function into an anonymous function:

// 🟢 Do
expect(() => functionWithError()).toThrow(Error)

// 🔴 Don’t
expect(functionWithError()).toThrow(Error)
expect(functionWithError('param')).toThrow(Error)

Copied to clipboard!

Notice that if you try to call the function directly inside the expect, it will fail the test as the error is not caught and the assertion will fail. You can also test other types of errors by passing the correct error to toThrow:

expect(functionWithError()).toThrow(EvalError)
expect(functionWithError()).toThrow(RangeError)
expect(functionWithError()).toThrow(ReferenceError)
expect(functionWithError()).toThrow(SyntaxError)
expect(functionWithError()).toThrow(TypeError)
expect(functionWithError()).toThrow(URIError)
expect(functionWithError()).toThrow(AggregateError)

Pass the correct type of error to test different types

Copied to clipboard!

Lastly, if you would like to test the error message itself, toThrow also accepts a string so you can test both the type and message:

const functionWithError = () => {
    throw new TypeError('Custom Error')
}

it('should throw an error', () => {
    expect(functionWithError).toThrow(TypeError)
    expect(functionWithError).toThrow('Custom Error')
})

Copied to clipboard!

How to Mock process.env in Jest

How to Mock process.env in JestUnit testing environment-specific parts in your applicationLearn how you can properly mock environment variables in your Jest tests to correctly test environment-specific parts in your application.

Когда вы пишете тесты, вам, как правило, необходимо проверять, что значения соответствуют определенным условиям. expect предоставляет вам доступ к ряду «проверок» (matchers), которые позволяют сопоставить результаты с ожиданиями.

Методы #


Справка #

expect(value) #

Функция expect используется каждый раз, когда вы хотите проверить значение. Однако, вам редко придется вызывать expect саму по себе. Вместо этого вы будете использовать expect вместе с функцией-проверкой для утверждения чего-либо о значении.

Это легче понять на примере. Скажем, у вас есть метод bestLaCroixFlavor(), который должен возвращать строку «грейпфрут». Вот как можно это протестировать:

test('лучший вкус это грейпфрут', () => {
  expect(bestLaCroixFlavor()).toBe('грейпфрут');
});

В данном случае для проверки значения используется функция toBe. Существует множество подобных функций, которые помогут вам тестировать различные вещи. Их список приведён ниже.

Аргументом для функции expect должно быть значение, которое возвращает ваш код, а в функцию проверки необходимо передавать ожидаемое верное значение. Если их перепутать местами, то тесты будут продолжать работать, а вот сообщения об ошибках в тестах будут выглядеть странно.

expect.extend(matchers) #

expect.extend используется для добавления новых проверок в Jest. Предположим, что вы тестируете библиотеку для работы с числами и вам довольно часто необходимо проверять, что числа делятся на другие числа без остатка. Тогда вы могли бы написать функцию toBeDivisibleBy, которая проверяет это:

expect.extend({
  toBeDivisibleBy(received, argument) {
    const pass = (received % argument == 0);
    if (pass) {
      return {
        message: () => (
          `ожидалось что ${received} не делится на ${argument}`
        ),
        pass: true,
      };
    } else {
      return {
        message: () => (`ожидалось что ${received} делится на ${argument}`),
        pass: false,
      };
    }
  },
});

Функции-проверки должны возвращать объект с двумя ключами. Ключ pass указывает было ли совпадение успешным или нет, а message представляет собой функцию без аргументов, которая возвращает сообщение об ошибке в случае проваленого теста. То есть, если pass имеет значение false, функция message должна возвращать сообщение об ошибке в случае если expect(x).yourMatcher() не выполняется. Когда же pass имеет значение true, функция message должна возвращать сообщение об ошибке в случае, если не выполняется expect(x).not.yourMatcher().

По ссылке this внутри пользовательской проверки можно получить доступ к следующим вспомогательным методам:

this.isNot #

Значение типа boolean, сигнализирующее о том, что функция была вызвана с модификатором отрицания .not, позволяющим инвертировать утверждение.

this.equals(a, b) #

Функция для проверки двух объектов на равенство (в т. ч. вложенных свойств). Возвращает значение типа boolean.

this.utils #

Существует целый ряд полезных инструментов доступных через this.utils и в основном состоящий из функций экспортируемых из jest-matcher-utils.

Наиболее полезными из них являются matcherHint, printExpected и printReceived для форматирования сообщений об ошибках. Например, взгляните как это реализовано для функции toBe:

const diff = require('jest-diff');
expect.extend({
  toBe(received, expected) {
    const pass = received === expected;

    const message = pass
      ? () => this.utils.matcherHint('.not.toBe') + 'nn' +
        `Expected value to not be (using ===):n` +
        `  ${this.utils.printExpected(expected)}n` +
        `Received:n` +
        `  ${this.utils.printReceived(received)}`
      : () => {
        const diffString = diff(expected, received, {
          expand: this.expand,
        });
        return this.utils.matcherHint('.toBe') + 'nn' +
        `Expected value to be (using ===):n` +
        `  ${this.utils.printExpected(expected)}n` +
        `Received:n` +
        `  ${this.utils.printReceived(received)}` +
        (diffString ? `nnDifference:nn${diffString}` : '');
      };

    return {actual: received, message, pass};
  },
});

Отобразится что-то вроде этого:

  expect(received).toBe(expected)

    Expected value to be (using ===):
      "banana"
    Received:
      "apple"

Когда утверждение становится ложным, сообщение об ошибке должно дать пользователю как можно больше информации, необходимой, чтобы быстро решить проблему. Поэтому, разрабатывая новые проверки, вам необходимо реализовывать в них точные и ясные сообщения об ошибках.

expect.anything() #

expect.anything() совпадает с любыми значениями, кроме null или undefined. Её можно использовать внутри toEqual или toBeCalledWith вместо литералов. Например, если вы хотите проверить, что функция-заглушка была вызвана с аргументом, не равным null:

test('map calls its argument with a non-null argument', () => {
  const mock = jest.fn();
  [1].map(mock);
  expect(mock).toBeCalledWith(expect.anything());
});

expect.any(constructor) #

expect.any(constructor) проверяет, что значение было создано с помощью данного конструктора. Её можно использовать внутри toEqual или toBeCalledWith вместо литералов. Например, если вы хотите проверить, что функция-заглушка была вызвана с аргументом типа число:

function randocall(fn) {
  return fn(Math.floor(Math.random() * 6 + 1));
}

test('randocall calls its callback with a number', () => {
  const mock = jest.fn();
  randocall(mock);
  expect(mock).toBeCalledWith(expect.any(Number));
});

expect.arrayContaining(array) #

expect.arrayContaining(array) проверяет, что данный массив содержит все элементы тестового. Иными словами, что тестовый массив является подмножеством данного. Отсюда в том числе следует, что этот массив может содержать элементы, которых нет в тестовом.

Можно использовать данный метод вместо литерала:

  • в функциях toEqual или toBeCalledWith
  • для проверки свойств объектов в objectContaining или toMatchObject
describe('arrayContaining', () => {
  const expected = ['Alice', 'Bob'];
  it('matches even if received contains additional elements', () => {
    expect(['Alice', 'Bob', 'Eve']).toEqual(expect.arrayContaining(expected));
  });
  it('does not match if received does not contain expected elements', () => {
    expect(['Bob', 'Eve']).not.toEqual(expect.arrayContaining(expected));
  });
});
describe('Beware of a misunderstanding! A sequence of dice rolls', () => {
  const expected = [1, 2, 3, 4, 5, 6];
  it('matches even with an unexpected number 7', () => {
    expect([4, 1, 6, 7, 3, 5, 2, 5, 4, 6])
      .toEqual(expect.arrayContaining(expected));
  });
  it('does not match without an expected number 2', () => {
    expect([4, 1, 6, 7, 3, 5, 7, 5, 4, 6])
      .not.toEqual(expect.arrayContaining(expected));
  });
});

expect.assertions(number) #

expect.assertions(number) проверяет, что во время выполнения теста было вызвано определённое число проверок. Это обычно полезно для тестирования асинхронного кода, чтобы удостовериться, что проверки действительно были вызваны в функциях обратного вызова.

Скажем, у нас есть функция doAsync, которая получает на вход две функции обратного вызова callback1 и callback2. Обе этих функции будут вызваны асинхронно в неизвестном заранее порядке. Это можно протестировать так:

test('doAsync calls both callbacks', () => {
  expect.assertions(2);
  function callback1(data) {
    expect(data).toBeTruthy();
  }
  function callback2(data) {
    expect(data).toBeTruthy();
  }

  doAsync(callback1, callback2);
});

Код expect.assertions(2) проверяет, что обе функции были вызваны.

expect.hasAssertions() #

expect.hasAssertions() проверяет, что во время выполнения теста была вызвана хотя бы одна проверка. Это обычно полезно для тестирования асинхронного кода, чтобы удостовериться, что проверки действительно были вызваны в функциях обратного вызова.

Предположим, что у нас есть несколько функций, которые работают с неким состоянием. prepareState запускает функцию обратного вызова с объектом состояния, validateState выполняет над этим объектом некую операцию, а waitOnState возвращает Promise, который ожидает, пока все фунцкии обратного вызова внутри prepareState не будут выполнены. Это можно протестировать так:

test('prepareState prepares a valid state', () => {
  expect.hasAssertions();
  prepareState(state => {
    expect(validateState(state)).toBeTruthy();
  });
  return waitOnState();
});

Код expect.hasAssertions() проверяет, что функция обратного вызова в prepareState была вызвана.

expect.objectContaining(object) #

expect.objectContaining(object) проверяет (рекурсивно), что данный объект имеет те или иные свойства. Иными словами, что тестовый объект является подмножеством данного. Отсюда в том числе следует, что этот объект может содержать свойста, которых нет в тестовом.

Instead of literal property values in the expected object, you can use matchers, expect.anything(), and so on.

Предположим, мы ожидаем, что функция onPress будет вызвана с объектом Event и всё, что мы хотим проверить — это то, что этот объект имеет свойства event.x и event.y. Это можно сделать так:

test('onPress gets called with the right thing', () => {
  const _onPress = jest.fn();
  simulatePresses(_onPress);
  expect(_onPress).toBeCalledWith(expect.objectContaining({
    x: expect.any(Number),
    y: expect.any(Number),
  }));
});

expect.stringContaining(string) #

доступно в версиях Jest 19.0.0+ #

expect.stringContaining(string) проверяет, что данная строка содержит в себе тестовую.

expect.stringMatching(regexp) #

expect.stringMatching(regexp) проверяет, что данная строка соответствует регулярному выражению.

Можно использовать данный метод вместо литерала:

  • в функциях toEqual или toBeCalledWith
  • для проверки элемента в arrayContaining
  • для проверки свойств объектов в objectContaining или toMatchObject

Следующий пример также демонстрирует, что вы можете вложить друг в друга несколько асимметричных проверок. В данном случае expect.stringMatching находится внутри expect.arrayContaining.

describe('stringMatching in arrayContaining', () => {
  const expected = [
    expect.stringMatching(/^Alic/),
    expect.stringMatching(/^[BR]ob/),
  ];
  it('matches even if received contains additional elements', () => {
    expect(['Alicia', 'Roberto', 'Evelina'])
      .toEqual(expect.arrayContaining(expected));
  });
  it('does not match if received does not contain expected elements', () => {
    expect(['Roberto', 'Evelina'])
      .not.toEqual(expect.arrayContaining(expected));
  });
});

expect.addSnapshotSerializer(serializer) #

Вы можете использовать expect.addSnapshotSerializer для добавления модуля, который поддерживает форматирование структур данных, специфичных для вашего приложения.

Для каждого файла, содержащего тесты, добавленный таким образом модуль будет предшествовать всем модулям, объявленным в параметре конфигурации snapshotSerializers. Те, в свою очередь, предшествуют сериализаторам снимков для встроенных типов JavaScript и элементов React, включённым в Jest по-умолчанию. Последний добавленный модуль будет протестирован первым.

import serializer from 'my-serializer-module';
expect.addSnapshotSerializer(serializer);

Если вы добавляете сериализатор снимков в файл с тестами вместо того, чтобы объявить его в параметре конфигурации snapshotSerializers, то:

  • Вы делаете зависимость явной.
  • Вы избегаете ограничений конфигурации, которые могут помешать вам использовать create-react-app.

Дополнительную информацию можно найти на странице [настройка Jest](/jest/docs/configuration. html#snapshotserializers-array-string).

.not #

Если вы знаете как можно проверить некое утверждение, то .not позволяет вам проверить обратное ему утверждение. Например, следующий код проверяет, что лучший вкус газировки La Croix не является кокосовым:

test('the best flavor is not coconut', () => {
  expect(bestLaCroixFlavor()).not.toBe('coconut');
});

.resolves #

доступно в версиях Jest 20.0.0+ #

Используйте resolves для возврата значения из объекта типа Promise. К возвращённому таким образом значению можно применять другие функции-проверки. Данный метод работает только с объектами Promise в состоянии «выполнено». Если объект Promise находится в состоянии «отклонено», то проверка не выполняется.

Например, следующий код проверяет, что Promise выполняется и результатом будет 'lemon':

test('resolves to lemon', () => {
  
  return expect(Promise.resolve('lemon')).resolves.toBe('lemon');
});

Кроме того, вы можете использовать async/await в комбинации с .resolves:

test('resolves to lemon', async () => {
  await expect(Promise.resolve('lemon')).resolves.toBe('lemon');
  await expect(Promise.resolve('lemon')).resolves.not.toBe('octopus');
});

.rejects #

доступно в версиях Jest 20.0.0+ #

Используйте .rejects для возврата значения из объекта типа Promise. К возвращённому таким образом значению можно применять другие функции-проверки. Данный метод работает только с объектами Promise в состоянии «отклонено». Если объект Promise находится в состоянии «выполнено», то проверка не выполняется.

Например, следующий код проверяет, что Promise отклонён с определённым сообщением об ошибке:

test('fetchData() rejects to be error', () => {
  
  return expect(Promise.reject('octopus')).rejects.toBeDefined();
});

Кроме того, вы можете использовать async/await в комбинации с .rejects. Следующий код проверяет, что сообщение об ошибке содержит ‘octopus’:

test('fetchData() rejects to be error', async () => {
  const drinkOctopus = new Promise(() => {
      throw new DisgustingFlavorError('yuck, octopus flavor');
  });

  await expect(drinkOctopus).rejects.toMatch('octopus');
});

.toBe(value) #

toBe просто проверяет, что значение соответствует ожидаемому. Эта функция использует строгую проверку на равенство ===.

For example, this code will validate some properties of the can object:

const can = {
  name: 'pamplemousse',
  ounces: 12,
};

describe('the can', () => {
  test('has 12 ounces', () => {
    expect(can.ounces).toBe(12);
  });

  test('has a sophisticated name', () => {
    expect(can.name).toBe('pamplemousse');
  });
});

Не следует использовать toBe для чисел с плавающей точкой. В JavaScript 0.2 + 0.1 не будет равно 0.3 из-за особенностей округления. Используйте .toBeCloseTo если вам необходимо сравнивать числа с плавающей точкой.

.toHaveBeenCalled() #

Другое имя функции: .toBeCalled()

Используйте .toHaveBeenCalled, чтобы убедиться, что функция-заглушка была вызвана.

Предположим, что у вас есть функция drinkAll(drink, flavor), которая принимает в качестве параметра функцию drink и вызывает её для всех напитков в вашей системе. Вам может потребоваться протестировать, что drink была вызвана для напитка 'lemon', но никак не для напитка 'octopus'. Было бы весьма странным иметь напиток со вкусом осьминога, не правда ли? Это можно сделать при помощи следующего теста:

describe('drinkAll', () => {
  test('drinks something lemon-flavored', () => {
    const drink = jest.fn();
    drinkAll(drink, 'lemon');
    expect(drink).toHaveBeenCalled();
  });

  test('does not drink something octopus-flavored', () => {
    const drink = jest.fn();
    drinkAll(drink, 'octopus');
    expect(drink).not.toHaveBeenCalled();
  });
});

.toHaveBeenCalledTimes(number) #

Используйте .toHaveBeenCalledTimes, чтобы убедиться, что функция-заглушка была вызвана строго определённое число раз.

Например, у вас может быть функция drinkEach(drink, Array<flavor>), которая принимает в качестве параметра функцию drink и вызывает её для каждого элемента массива напитков. Тогда вам может потребоваться проверить, что функция drink была вызвана определённое число раз. Это можно сделать при помощи следующего теста:

test('drinkEach drinks each drink', () => {
  const drink = jest.fn();
  drinkEach(drink, ['lemon', 'octopus']);
  expect(drink).toHaveBeenCalledTimes(2);
});

.toHaveBeenCalledWith(arg1, arg2, ...) #

Also under the alias: .toBeCalledWith()

Используйте .toHaveBeenCalledWith, чтобы убедиться, что функция-заглушка была вызвана с определённым набором аргументов.

Предположим, что у вас есть функция register, которая добавляет напиток в систему, а также функция applyToAll(f), должна применить функцию f ко всем напиткам. Чтобы убедиться, что это работает, вы могли бы написать:

test('registration applies correctly to orange La Croix', () => {
  const beverage = new LaCroix('orange');
  register(beverage);
  const f = jest.fn();
  applyToAll(f);
  expect(f).toHaveBeenCalledWith(beverage);
});

.toHaveBeenLastCalledWith(arg1, arg2, ...) #

Другое имя функции: .lastCalledWith(arg1, arg2, ...)

Используйте .toHaveBeenLastCalledWith, чтобы убедиться, что в последний раз функция-заглушка была вызвана с определённым набором аргументов. Например, ваша функция applyToAllFlavors(f) вызывает функцию drink для набора напитков. Вы хотите убедиться, что последним был вызван напиток 'mango'. Вы можете написать:

test('applying to all flavors does mango last', () => {
  const drink = jest.fn();
  applyToAllFlavors(drink);
  expect(drink).toHaveBeenLastCalledWith('mango');
});

.toBeCloseTo(number, numDigits) #

Использовать оператор равенства для сравнения чисел с плавающей точкой — это плохая идея. Когда работает округление, перестают работать очевидные вещи. Нпример, этот тест не будет пройден:

test('adding works sanely with simple decimals', () => {
  expect(0.2 + 0.1).toBe(0.3); 
});

А неверно это потому, что в JavaScript 0.2 + 0.1 равно 0.30000000000000004. Уж извините.

Вместо этого используйте .toBeCloseTo. Параметр numDigits определяет сколько разрядов после запятой необходимо учитывать. Например, если вам нужно убедиться, что 0.2 + 0.1 равно 0.3 с точностью до пяти знаков после запятой, можно написать следующее:

test('adding works sanely with simple decimals', () => {
  expect(0.2 + 0.1).toBeCloseTo(0.3, 5);
});

По-умолчанию numDigits равен 2, что в большинстве случаев достаточно.

.toBeDefined() #

Используйте .toBeDefined для проверки того, что переменная определена. Например, если вы просто хотите проверить, что функция fetchNewFlavorIdea() возвращает что-то, вы можете написать:

test('there is a new flavor idea', () => {
  expect(fetchNewFlavorIdea()).toBeDefined();
});

Конечно, можно было бы написать expect(fetchNewFlavorIdea()).not.toBe(undefined), но лучше избегать использования undefined непосредственно в вашем коде.

.toBeFalsy() #

Используйте .toBeFalsy когда вам всего лишь необходимо проверить, что значение эквивалентно ложному. Предположим, что у вас есть следующий код:

drinkSomeLaCroix();
if (!getErrors()) {
  drinkMoreLaCroix();
}

Вам не так уж важно что возвращает getErrors. Она может вернуть false, null или «, однако ваш код будет корректно работать. И если вы хотите протестировать, что после употребления газировки La Croix не произошло никаких ошибок, то можно написать:

test('drinking La Croix does not lead to errors', () => {
  drinkSomeLaCroix();
  expect(getErrors()).toBeFalsy();
});

В JavaScript существует всего шесть значений, эквивалетных ложному: false, `,»,null,undefinedиNaN`. Всё остальное эквивалентно истине.

.toBeGreaterThan(number) #

Для сравнения чисел с плавающей точкой можно использовать toBeGreaterThan. Например, если вы хотите проверить, что ouncesPerCan() возвращает значение, которое больше чем 10 унций, пишите:

test('ounces per can is more than 10', () => {
  expect(ouncesPerCan()).toBeGreaterThan(10);
});

.toBeGreaterThanOrEqual(number) #

Для сравнения чисел с плавающей точкой можно использовать toBeGreaterThanOrEqual. Например, если вы хотите проверить, что ouncesPerCan() возвращает значение, которое не меньше чем 12 унций, пишите:

test('ounces per can is at least 12', () => {
  expect(ouncesPerCan()).toBeGreaterThanOrEqual(12);
});

.toBeLessThan(number) #

Для сравнения чисел с плавающей точкой можно использовать toBeLessThan. Например, если вы хотите проверить, что ouncesPerCan() возвращает значение, которое меньше чем 20 унций, пишите:

test('ounces per can is less than 20', () => {
  expect(ouncesPerCan()).toBeLessThan(20);
});

.toBeLessThanOrEqual(number) #

Для сравнения чисел с плавающей точкой можно использовать toBeLessThanOrEqual. Например, если вы хотите проверить, что ouncesPerCan() возвращает значение, которое не больше чем 12 унций, пишите:

test('ounces per can is at most 12', () => {
  expect(ouncesPerCan()).toBeLessThanOrEqual(12);
});

.toBeInstanceOf(Class) #

Используйте .toBeInstanceOf(Class), чтобы проверить, что данный объект является экземпляром того или иного класса. Эта функция использует оператор instanceof.

class A {}

expect(new A()).toBeInstanceOf(A);
expect(() => {}).toBeInstanceOf(Function);
expect(new A()).toBeInstanceOf(Function); 

.toBeNull() #

.toBeNull() ведёт себя точно так же, как .toBe(null), просто её сообщения об ошибках выглядят получше. Так что, если вам нужно проверить, что что-то является null, то используйте .toBeNull().

function bloop() {
  return null;
}

test('bloop returns null', () => {
  expect(bloop()).toBeNull();
});

.toBeTruthy() #

Используйте .toBeTruthy когда вам всего лишь необходимо проверить, что значение эквивалентно истинному. Предположим, что у вас есть следующий код:

drinkSomeLaCroix();
if (thirstInfo()) {
  drinkMoreLaCroix();
}

Вам не так уж важно, что возвращает thirstInfo. Она может вернуть true или целый объект, однако ваш код будет корректно работать. Так что если вы просто хотите проверить, что thirstInfo вернёт значение эквивалетное истинному после употребления газировки La Croix, можно написать:

test('drinking La Croix leads to having thirst info', () => {
  drinkSomeLaCroix();
  expect(thirstInfo()).toBeTruthy();
});

В JavaScript существует всего шесть значений, эквивалетных ложному: false, `,»,null,undefinedиNaN`. Всё остальное эквивалентно истине.

.toBeUndefined() #

Используйте .toBeUndefined, чтобы проверить, что переменная не определена. Например, вы хотите проверить, что функция bestDrinkForFlavor(flavor) возвращает undefined для вкуса 'octopus'. Просто потому, что напитков со вкусом осьминога не существует:

test('the best drink for octopus flavor is undefined', () => {
  expect(bestDrinkForFlavor('octopus')).toBeUndefined();
});

Конечно, можно было бы написать expect(bestDrinkForFlavor('octopus')).toBe(undefined), но лучше избегать использования undefined непосредственно в вашем коде.

.toContain(item) #

Используйте .toContain если вы хотите убедиться, что тот или иной элемент находится в списке. Эта функция использует оператор строгого равенства ===.

Например, если getAllFlavors() возвращает список вкусов, и вы хотите быть уверены, что в нём присутствует lime, то вы можете написать:

test('the flavor list contains lime', () => {
  expect(getAllFlavors()).toContain('lime');
});

.toContainEqual(item) #

Используйте .toContainEqual если вы хотите убедиться, что тот или иной элемент находится в списке. Вместо проверки объектов на идентичность, эта функция рекурсивно сравнивает все поля в объектах.

describe('my beverage', () => {
  test('is delicious and not sour', () => {
    const myBeverage = {delicious: true, sour: false};
    expect(myBeverages()).toContainEqual(myBeverage);
  });
});

.toEqual(value) #

Используйте .toEqual, когда вы хотите проверить, что два объекта имеют одинаковое значение. Вместо проверки объектов на идентичность, эта функция рекурсивно сравнивает все поля в объектах. Эта процедура ещё называется «проверка на глубокое равенство». Например toEqual и toBe ведут себя по-разному в этом наборе, и, таким образом, все тесты успешно выполняются:

const can1 = {
  flavor: 'grapefruit',
  ounces: 12,
};
const can2 = {
  flavor: 'grapefruit',
  ounces: 12,
};

describe('the La Croix cans on my desk', () => {
  test('have all the same properties', () => {
    expect(can1).toEqual(can2);
  });
  test('are not the exact same can', () => {
    expect(can1).not.toBe(can2);
  });
});

Примечание: .toEqual не сможет выполнить проверку на глубокое равенство для объектов типа Error. В этих объектах проверяется на равенство только свойство message. Поэтому для тестирования исключений рекомендуется использовать функцию .toThrow.

.toHaveLength(number) #

Используйте .toHaveLength для проверки того, что объект имеет свойство .length, и оно имеет определённое значение.

Это особенно полезно для проверки размера массивов или строк.

expect([1, 2, 3]).toHaveLength(3);
expect('abc').toHaveLength(3);
expect('').not.toHaveLength(5);

.toMatch(regexpOrString) #

Используйте .toMatch, чтобы проверить, что строка соответствует регулярному выражению.

Например, вы можете не знать точное возвращаемое значение функции essayOnTheBestFlavor(), однако вы уверены, что это — очень длинная строка в которой содержится слово grapefruit. Это можно протестировать так:

describe('an essay on the best flavor', () => {
  test('mentions grapefruit', () => {
    expect(essayOnTheBestFlavor()).toMatch(/grapefruit/);
    expect(essayOnTheBestFlavor()).toMatch(new RegExp('grapefruit'));
  });
});

Кроме того, эта функция может принимать и строку, которую попытается найти в исходной:

describe('grapefruits are healthy', () => {
  test('grapefruits are a fruit', () => {
    expect('grapefruits').toMatch('fruit');
  });
});

.toMatchObject(object) #

Используйте .toMatchObject для проверки того, что некий объект содержит подмножество свойств текущего объекта. It will match received objects with properties that are not in the expected object.

You can also pass an array of objects, in which case the method will return true only if each object in the received array matches (in the toMatchObject sense described above) the corresponding object in the expected array. This is useful if you want to check that two arrays match in their number of elements, as opposed to arrayContaining, which allows for extra elements in the received array.

You can match properties against values or against matchers.

const houseForSale = {
  bath: true,
  bedrooms: 4,
  kitchen: {
    amenities: ['oven', 'stove', 'washer'],
    area: 20,
    wallColor: 'white',
  },
};
const desiredHouse = {
  bath: true,
  kitchen: {
    amenities: ['oven', 'stove', 'washer'],
    wallColor: expect.stringMatching(/white|yellow/),
  },
};

test('the house has my desired features', () => {
  expect(houseForSale).toMatchObject(desiredHouse);
});
describe('toMatchObject applied to arrays arrays', () => {
  test('the number of elements must match exactly', () => {
    expect([
      { foo: 'bar' },
      { baz: 1 }
    ]).toMatchObject([
      { foo: 'bar' },
      { baz: 1 }
    ]);
  });

  
  test('.toMatchObject does not allow extra elements', () => {
    expect([
      { foo: 'bar' },
      { baz: 1 }
    ]).toMatchObject([
      { foo: 'bar' }
    ]);
  });

  test('.toMatchObject is called for each elements, so extra object properties are okay', () => {
    expect([
      { foo: 'bar' },
      { baz: 1, extra: 'quux' }
    ]).toMatchObject([
      { foo: 'bar' },
      { baz: 1 }
    ]);
  });
});

.toHaveProperty(keyPath, value) #

Используйте .toHaveProperty для проверки того, что в данном объекте есть свойство keyPath. Для проверки глубоко вложенных свойств используйте точечную нотацию.

Кроме того, можно указать параметр value для проверки того, что значение свойства keyPath в объекте соответствует заданному. Эта функция использует «глубокое равенство» (как и toEqual()) и проверяет равенство полей рекурсивно.

В следующем примере содержится объект houseForSale с вложенными свойствами. Мы используем toHaveProperty для проверки существования и значений некоторых свойств в объекте.

const houseForSale = {
  bath: true,
  bedrooms: 4,
  kitchen: {
    amenities: ['oven', 'stove', 'washer'],
    area: 20,
    wallColor: 'white',
  },
};

test('this house has my desired features', () => {
  
  expect(houseForSale).toHaveProperty('bath');
  expect(houseForSale).toHaveProperty('bedrooms', 4);

  expect(houseForSale).not.toHaveProperty('pool');

  
  expect(houseForSale).toHaveProperty('kitchen.area', 20);
  expect(houseForSale).toHaveProperty('kitchen.amenities', [
    'oven',
    'stove',
    'washer',
  ]);

  expect(houseForSale).not.toHaveProperty('kitchen.open');
});

.toMatchSnapshot(optionalString) #

Проверяет, что значение соответствует наиболее свежему снимку. За дополнительной информацией обращайтесь к разделу Тестирование при помощи снимков.

В функцию можно передать имя снимка. В противном случае имя определяется из теста.

Примечание: тестирование при помощи снимков, как правило, применяется к компонентам React. Тем не менее, любое сериализуемое значение может быть использовано в качестве снимка.

.toThrow(error) #

Другое имя функции: .toThrowError()

Используйте .toThrow для проверки, что функция бросает исключение при вызове. Например, если бы мы хотели проверить, что функция drinkFlavor('octopus') кидает исключение, потому что газировка со вкусом осьминога слишком отвратительна для питья, мы могли бы написать:

test('throws on octopus', () => {
  expect(() => {
    drinkFlavor('octopus');
  }).toThrow();
});

Если вы хотите проверить, что было выброшено то или иное исключение, то можно передать аргумент в toThrow. Этим аргументом может быть строка с сообщением об ошибке, класс исключения или регулярное выражение. Пусть в drinkFlavor написано следующее:

function drinkFlavor(flavor) {
  if (flavor == 'octopus') {
    throw new DisgustingFlavorError('yuck, octopus flavor');
  }
  
}

Мы можем проверить это исключение несколькими способами:

test('throws on octopus', () => {
  function drinkOctopus() {
    drinkFlavor('octopus');
  }

  
  expect(drinkOctopus).toThrowError('yuck, octopus flavor');

  
  expect(drinkOctopus).toThrowError(/yuck/);

  
  expect(drinkOctopus).toThrowError(DisgustingFlavorError);
});

.toThrowErrorMatchingSnapshot() #

Use .toThrowErrorMatchingSnapshot to test that a function throws an error matching the most recent snapshot when it is called. Например, у вас есть функция drinkFlavor, которая генерирует исключение всякий раз, когда ей передают параметр 'octopus':

function drinkFlavor(flavor) {
  if (flavor == 'octopus') {
    throw new DisgustingFlavorError('yuck, octopus flavor');
  }
  
}

Тест для этой функции будет выглядеть следующим образом:

test('throws on octopus', () => {
  function drinkOctopus() {
    drinkFlavor('octopus');
  }

  expect(drinkOctopus).toThrowErrorMatchingSnapshot();
});

Этот тест создаст следующий снимок:

exports[`drinking flavors throws on octopus 1`] = `"yuck, octopus flavor"`;

Дополнительную информацию по тестированию при помощи снимков можно найти на странице React Tree Snapshot Testing.

Возможно, вам также будет интересно:

  • Jenkins ошибка обработки запроса logging id
  • Jeep ошибка c141d rear differential control circuit low
  • Jeep grand cherokee ошибка p1492
  • Jeep grand cherokee ошибка p0340
  • Java lang nullpointerexception group ошибка

  • Понравилась статья? Поделить с друзьями:
    0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии