Agenda
- The goal of this post
- expect.assertions(number) rather than done()
- .rejects rather than try-catch
- .toThrow rather than toMatch or toEqual
- Use-case 1: Handle Error in a function
- Use-case 2: Handle Error in an asynchronous function
- 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
Зарегистрируйтесь для доступа к 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 ₽ в месяц
Разработка фронтенд- и бэкенд-компонентов для веб-приложений
Автоматизированное тестирование веб-приложений на 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
PeterDanisPeterDanis
8,3402 gold badges13 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 DrozdPaweł BB Drozd
4,5234 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')
answered May 23, 2019 at 8:46
Tal JoffeTal Joffe
5,3774 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.
answered Sep 25, 2019 at 17:27
Kenny BodyKenny Body
1,0698 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
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 BaginovSlava Baginov
9691 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.
answered May 24, 2020 at 7:05
AdrianAdrian
1,68310 silver badges6 bronze badges
4
In case you are working with Promise
s:
await expect(Promise.reject(new HttpException('Error message', 402)))
.rejects.toThrowError(HttpException);
answered Jan 28, 2020 at 22:30
Željko ŠevićŽeljko Šević
3,7732 gold badges26 silver badges23 bronze badges
2
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
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
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 HabhabSafi Habhab
98110 silver badges17 bronze badges
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.
answered Sep 4, 2017 at 18:48
Andrei CACIOAndrei CACIO
2,10115 silver badges28 bronze badges
I have successfully used this
await expect(
async () => await apiCalls()
).rejects.toThrow();
answered Feb 28, 2022 at 20:00
Liu HantaoLiu Hantao
6181 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.
answered Sep 4, 2017 at 18:49
alexmacalexmac
19.1k7 gold badges58 silver badges69 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()
})
})
answered Dec 14, 2019 at 15:12
redeemefyredeemefy
4,5416 gold badges36 silver badges52 bronze badges
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 to have the full error message. As long as your error contains part of the error message we can assume that 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 YaqoobiYasin Yaqoobi
1,9183 gold badges27 silver badges38 bronze badges
1
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
kpollockkpollock
3,9099 gold badges42 silver badges62 bronze badges
2
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 LuoKaiwen Luo
3804 silver badges10 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 OmeiriOmar Omeiri
1,5261 gold badge17 silver badges33 bronze badges
If you want something less verbose in your tests but want to test an Error is of a class and has a certain message (or status, or any other properties), you can write a custom matcher.
We use something pretty simple, but you can extend this to include RegExp, etc.
// In jest.setup.js
expect.extend({
toThrowErrorWithMessage: (received, errorType, message) => {
if (!received) {
return {
message: () =>
`expected error to be of type ${errorType.name} with message matching ${message}, received ${received}`,
pass: false,
};
}
if (!(received instanceof errorType)) {
return {
message: () => `expected error of type ${errorType} received ${received}`,
pass: false,
};
}
const validMessage = received.message && received.message.match(message);
if (!validMessage) {
return {
message: () =>
`expected error message to match "${message}", received "${received.message}"`,
pass: false,
};
}
return {
pass: true,
// Note: this message is for when using .not
message: () =>
`expected error not to be of type ${errorType.name} with message matching "${message}"`,
};
},
});
// In a test
expect(() => validate()).rejects.toThrowErrorWithMessage(BadRequestError, 'Oh noes')
answered Jul 8 at 13:34
Similar to the try/catch, if you are looking to catch an error for an async function one can also just append a .catch() to the function to be able to access error value:
await asyncFunc().catch(e => { expect(e.toString()).toBe("Error: My error message") })
or whatever functionality you are looking to test
answered Jul 25 at 17:16
Jest version: 29
You have an async function that needs to be tested for throwing an error.
await expect(listener.onMessage(data, msg)).rejects.toThrow();
Assert with exact error message:
await expect(listener.onMessage(data, msg)).rejects.toThrow("Data not found!");
answered Jul 30 at 3:28
Try:
expect(t).rejects.toThrow()
answered May 16, 2019 at 16:37
2
Когда вы пишете тесты, вам, как правило, необходимо проверять, что значения соответствуют определенным условиям. 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') + '\n\n' + `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') + '\n\n' + `Expected value to be (using ===):\n` + ` ${this.utils.printExpected(expected)}\n` + `Received:\n` + ` ${this.utils.printReceived(received)}` + (diffString ? `\n\nDifference:\n\n${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.
Когда вы пишете тесты, вам часто нужно проверить, соответствуют ли значения определенным условиям. expect
дает вам доступ к ряду «сопоставителей», которые позволяют вам проверять разные вещи.
Чтобы узнать о дополнительных сопоставителях Jest, поддерживаемых сообществом Jest, ознакомьтесь с jest-extended
.
Methods
expect(value)
expect.extend(matchers)
expect.anything()
expect.any(constructor)
expect.arrayContaining(array)
expect.assertions(number)
expect.closeTo(number, numDigits?)
expect.hasAssertions()
expect.not.arrayContaining(array)
expect.not.objectContaining(object)
expect.not.stringContaining(string)
expect.not.stringMatching(string | regexp)
expect.objectContaining(object)
expect.stringContaining(string)
expect.stringMatching(string | regexp)
expect.addSnapshotSerializer(serializer)
.not
.resolves
.rejects
.toBe(value)
.toHaveBeenCalled()
.toHaveBeenCalledTimes(number)
.toHaveBeenCalledWith(arg1, arg2, ...)
.toHaveBeenLastCalledWith(arg1, arg2, ...)
.toHaveBeenNthCalledWith(nthCall, arg1, arg2, ....)
.toHaveReturned()
.toHaveReturnedTimes(number)
.toHaveReturnedWith(value)
.toHaveLastReturnedWith(value)
.toHaveNthReturnedWith(nthCall, value)
.toHaveLength(number)
.toHaveProperty(keyPath, value?)
.toBeCloseTo(number, numDigits?)
.toBeDefined()
.toBeFalsy()
.toBeGreaterThan(number | bigint)
.toBeGreaterThanOrEqual(number | bigint)
.toBeLessThan(number | bigint)
.toBeLessThanOrEqual(number | bigint)
.toBeInstanceOf(Class)
.toBeNull()
.toBeTruthy()
.toBeUndefined()
.toBeNaN()
.toContain(item)
.toContainEqual(item)
.toEqual(value)
.toMatch(regexp | string)
.toMatchObject(object)
.toMatchSnapshot(propertyMatchers?, hint?)
.toMatchInlineSnapshot(propertyMatchers?, inlineSnapshot)
.toStrictEqual(value)
.toThrow(error?)
.toThrowErrorMatchingSnapshot(hint?)
.toThrowErrorMatchingInlineSnapshot(inlineSnapshot)
Reference
expect(value)
Функция expect
используется каждый раз, когда вы хотите проверить значение. Вы редко будете вызывать expect
само по себе. Вместо этого вы будете использовать expect
вместе с функцией «сопоставления», чтобы что-то утверждать о значении.
Это проще понять на примере. Допустим, у вас есть метод bestLaCroixFlavor()
который должен возвращать строку 'grapefruit'
. Вот как это проверить:
test('the best flavor is grapefruit', () => { expect(bestLaCroixFlavor()).toBe('grapefruit'); });
В этом случае toBe
сопоставления toBe . Существует множество различных функций сопоставления, которые описаны ниже, чтобы помочь вам тестировать разные вещи.
Аргумент expect
должен быть значением , которое производит ваш код, и любой аргумент согласовани должен быть правильным значением. Если вы их перепутаете, ваши тесты все равно будут работать, но сообщения об ошибках при неудачных тестах будут выглядеть странно.
expect.extend(matchers)
Вы можете использовать expect.extend
, чтобы добавлять в Jest собственные сопоставления. Например, предположим, что вы тестируете библиотеку утилит для чисел и часто утверждаете, что числа появляются в определенных диапазонах других чисел. Вы можете абстрагировать это в сопоставлении toBeWithinRange
:
expect.extend({ toBeWithinRange(received, floor, ceiling) { const pass = received >= floor && received <= ceiling; if (pass) { return { message: () => `expected ${received} not to be within range ${floor} - ${ceiling}`, pass: true, }; } else { return { message: () => `expected ${received} to be within range ${floor} - ${ceiling}`, pass: false, }; } }, }); test('numeric ranges', () => { expect(100).toBeWithinRange(90, 110); expect(101).not.toBeWithinRange(0, 100); expect({apples: 6, bananas: 3}).toEqual({ apples: expect.toBeWithinRange(1, 10), bananas: expect.not.toBeWithinRange(11, 20), }); });
note
Например, в TypeScript при использовании @types/jest
вы можете объявить новый toBeWithinRange
в импортированном модуле следующим образом:
interface CustomMatchers<R = unknown> { toBeWithinRange(floor: number, ceiling: number): R; } declare global { namespace jest { interface Expect extends CustomMatchers {} interface Matchers<R> extends CustomMatchers<R> {} interface InverseAsymmetricMatchers extends CustomMatchers {} } }
Async Matchers
expect.extend
также поддерживает асинхронные сопоставления. Асинхронные сопоставители возвращают обещание, поэтому вам нужно будет дождаться возвращенного значения. Давайте использовать пример сопоставления, чтобы проиллюстрировать их использование. Мы собираемся реализовать сопоставление под названием toBeDivisibleByExternalValue
, где делимое число будет извлекаться из внешнего источника.
expect.extend({ async toBeDivisibleByExternalValue(received) { const externalValue = await getExternalValueFromRemoteSource(); const pass = received % externalValue == 0; if (pass) { return { message: () => `expected ${received} not to be divisible by ${externalValue}`, pass: true, }; } else { return { message: () => `expected ${received} to be divisible by ${externalValue}`, pass: false, }; } }, }); test('is divisible by external value', async () => { await expect(100).toBeDivisibleByExternalValue(); await expect(101).not.toBeDivisibleByExternalValue(); });
API пользовательских матчей
Сопоставители должны возвращать объект (или обещание объекта) с двумя ключами. pass
указывает, было совпадение или нет, а message
предоставляет функцию без аргументов, которая возвращает сообщение об ошибке в случае сбоя. Таким образом, когда pass
имеет значение false, message
должно возвращать сообщение об ошибке, когда expect(x).yourMatcher()
терпит неудачу. И когда pass
имеет значение true, message
должно возвращать сообщение об ошибке, когда expect(x).not.yourMatcher()
терпит неудачу.
Сопоставители вызываются с аргументом, переданным в expect(x)
за которым следуют аргументы, переданные в .yourMatcher(y, z)
:
expect.extend({ yourMatcher(x, y, z) { return { pass: true, message: () => '', }; }, });
Эти вспомогательные функции и свойства могут быть найдены на this
внутри пользовательской согласовани:
this.isNot
.not
значение, чтобы вы знали, что этот сопоставитель был вызван с модификатором negated .not , позволяющим отображать четкую и правильную подсказку сопоставления (см. Пример кода).
this.promise
Строка,позволяющая отобразить четкую и правильную подсказку о матчере:
-
'rejects'
, если сопоставление было.rejects
модификатором обещания .rejects -
'resolves'
если сопоставление было.resolves
модификатором обещания .resolves -
''
если сопоставление не было вызвано с модификатором обещания
this.equals(a, b)
Это функция глубокого равенства, которая вернет true
если два объекта имеют одинаковые значения (рекурсивно).
this.expand
Логический , чтобы вы знали это согласовань была вызвана с expand
опции. Когда Jest вызывается с флагом --expand
, this.expand
может использоваться, чтобы определить, должен ли Jest показывать полные различия и ошибки.
this.utils
На this.utils
есть ряд полезных инструментов, в основном состоящих из экспорта из jest-matcher-utils
.
Наиболее полезными из них являются matcherHint
, printExpected
и printReceived
для удобного форматирования сообщений об ошибках. Например, посмотрите на реализацию toBe
:
const {diff} = require('jest-diff'); expect.extend({ toBe(received, expected) { const options = { comment: 'Object.is equality', isNot: this.isNot, promise: this.promise, }; const pass = Object.is(received, expected); const message = pass ? () => this.utils.matcherHint('toBe', undefined, undefined, options) + '\n\n' + `Expected: not ${this.utils.printExpected(expected)}\n` + `Received: ${this.utils.printReceived(received)}` : () => { const diffString = diff(expected, received, { expand: this.expand, }); return ( this.utils.matcherHint('toBe', undefined, undefined, options) + '\n\n' + (diffString && diffString.includes('- Expect') ? `Difference:\n\n${diffString}` : `Expected: ${this.utils.printExpected(expected)}\n` + `Received: ${this.utils.printReceived(received)}`) ); }; return {actual: received, message, pass}; }, });
Это напечатает что-то вроде этого:
expect(received).toBe(expected) Expected value to be (using Object.is): "banana" Received: "apple"
Когда утверждение не удается,сообщение об ошибке должно давать столько сигнала,сколько необходимо пользователю,чтобы он мог быстро решить свою проблему.Вы должны создать точное сообщение об ошибке,чтобы убедиться,что пользователи ваших пользовательских утверждений имеют хороший опыт работы с разработчиками.
Пользовательские снимки матчей
Чтобы использовать тестирование снимков внутри вашего настраиваемого сопоставителя, вы можете импортировать jest-snapshot
и использовать его из своего сопоставителя.
Вот средство сопоставления снимков, которое обрезает строку для сохранения заданной длины, .toMatchTrimmedSnapshot(length)
:
const {toMatchSnapshot} = require('jest-snapshot'); expect.extend({ toMatchTrimmedSnapshot(received, length) { return toMatchSnapshot.call( this, received.substring(0, length), 'toMatchTrimmedSnapshot', ); }, }); it('stores only 10 characters', () => { expect('extra long string oh my gerd').toMatchTrimmedSnapshot(10); });
Также можно создавать пользовательские матчики для инлайн-снимков,при этом снимки будут корректно добавляться в пользовательские матчики.Однако inline snapshot всегда будет пытаться добавлять к первому аргументу или второму,если первый аргумент-это property matcher,поэтому невозможно принимать пользовательские аргументы в пользовательских matchers.
const {toMatchInlineSnapshot} = require('jest-snapshot'); expect.extend({ toMatchTrimmedInlineSnapshot(received, ...rest) { return toMatchInlineSnapshot.call(this, received.substring(0, 10), ...rest); }, }); it('stores only 10 characters', () => { expect('extra long string oh my gerd').toMatchTrimmedInlineSnapshot(); });
async
Если ваш пользовательский встроенный сопоставитель снимков является асинхронным, то есть использует async
— await
, вы можете столкнуться с ошибкой типа «Несколько встроенных снимков для одного и того же вызова не поддерживаются». Jest нужна дополнительная контекстная информация, чтобы найти, где пользовательское встроенное сопоставление снимков использовалось для правильного обновления снимков.
const {toMatchInlineSnapshot} = require('jest-snapshot'); expect.extend({ async toMatchObservationInlineSnapshot(fn, ...rest) { this.error = new Error(); const observation = await observe(async () => { await fn(); }); return toMatchInlineSnapshot.call(this, recording, ...rest); }, }); it('observes something', async () => { await expect(async () => { return 'async action'; }).toMatchTrimmedInlineSnapshot(); });
Bail out
Обычно jest
пытается сопоставить каждый снимок, который ожидается в тесте.
Иногда не имеет смысла продолжать тест,если предыдущий снимок оказался неудачным.Например,когда вы делаете снимки машины состояний после различных переходов,вы можете прервать тест,если один переход привел к неправильному состоянию.
В этом случае вы можете реализовать пользовательский snapshot matcher,который бросает при первом несоответствии вместо того,чтобы собирать каждое несоответствие.
const {toMatchInlineSnapshot} = require('jest-snapshot'); expect.extend({ toMatchStateInlineSnapshot(...args) { this.dontThrow = () => {}; return toMatchInlineSnapshot.call(this, ...args); }, }); let state = 'initial'; function transition() { if (state === 'INITIAL') { state = 'pending'; } else if (state === 'pending') { state = 'done'; } } it('transitions as expected', () => { expect(state).toMatchStateInlineSnapshot(`"initial"`); transition(); expect(state).toMatchStateInlineSnapshot(`"loading"`); transition(); expect(state).toMatchStateInlineSnapshot(`"done"`); });
expect.anything()
expect.anything()
соответствует чему угодно, кроме null
или undefined
. Вы можете использовать его внутри toEqual
или toBeCalledWith
вместо буквального значения. Например, если вы хотите проверить, что фиктивная функция вызывается с ненулевым аргументом:
test('map calls its argument with a non-null argument', () => { const mock = jest.fn(); [1].map(x => mock(x)); expect(mock).toBeCalledWith(expect.anything()); });
expect.any(constructor)
expect.any(constructor)
соответствует всему, что было создано с помощью данного конструктора, или если это примитив переданного типа. Вы можете использовать его внутри toEqual
или toBeCalledWith
вместо буквального значения. Например, если вы хотите проверить, вызывается ли фиктивная функция с числом:
class Cat {} function getCat(fn) { return fn(new Cat()); } test('randocall calls its callback with a class instance', () => { const mock = jest.fn(); getCat(mock); expect(mock).toBeCalledWith(expect.any(Cat)); }); 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.closeTo(number, numDigits?)
expect.closeTo(number, numDigits?)
полезен при сравнении чисел с плавающей запятой в свойствах объекта или элементе массива. Если вам нужно сравнить число, используйте вместо него .toBeCloseTo
.
Необязательный аргумент numDigits
ограничивает количество проверяемых цифр после запятой. Для значения по умолчанию 2
критерием проверки является Math.abs(expected - received) < 0.005 (that is, 10 ** -2 / 2)
.
Например,этот тест проходит с точностью до 5 цифр:
test('compare float in object properties', () => { expect({ title: '0.1 + 0.2', sum: 0.1 + 0.2, }).toEqual({ title: '0.1 + 0.2', sum: expect.closeTo(0.3, 5), }); });
expect.hasAssertions()
expect.hasAssertions()
проверяет, что во время теста вызывается хотя бы одно утверждение. Это часто бывает полезно при тестировании асинхронного кода, чтобы убедиться, что утверждения в обратном вызове действительно вызываются.
Например, предположим, что у нас есть несколько функций, которые все имеют дело с состоянием. prepareState
вызывает обратный вызов с объектом состояния, validateState
запускается для этого объекта состояния, а waitOnState
возвращает обещание, которое ожидает завершения всех prepareState
вызовов prepareState . Мы можем проверить это с помощью:
test('prepareState prepares a valid state', () => { expect.hasAssertions(); prepareState(state => { expect(validateState(state)).toBeTruthy(); }); return waitOnState(); });
В expect.hasAssertions()
гарантирует , что вызов prepareState
обратного вызова на самом деле вызывается.
expect.not.arrayContaining(array)
expect.not.arrayContaining(array)
соответствует полученному массиву, который не содержит всех элементов ожидаемого массива. То есть ожидаемый массив не является подмножеством полученного массива.
Это противоположность expect.arrayContaining
.
describe('not.arrayContaining', () => { const expected = ['Samantha']; it('matches if the actual array does not contain the expected elements', () => { expect(['Alice', 'Bob', 'Eve']).toEqual( expect.not.arrayContaining(expected), ); }); });
expect.not.objectContaining(object)
expect.not.objectContaining(object)
соответствует любому полученному объекту, который рекурсивно не соответствует ожидаемым свойствам. То есть ожидаемый объект не является подмножеством полученного объекта. Следовательно, он соответствует полученному объекту, который содержит свойства, которых нет в ожидаемом объекте.
Это противоположность expect.objectContaining
.
describe('not.objectContaining', () => { const expected = {foo: 'bar'}; it('matches if the actual object does not contain expected key: value pairs', () => { expect({bar: 'baz'}).toEqual(expect.not.objectContaining(expected)); }); });
expect.not.stringContaining(string)
expect.not.stringContaining(string)
соответствует полученному значению, если оно не является строкой или если это строка, не содержащая точной ожидаемой строки.
Это противоположность expect.stringContaining
.
describe('not.stringContaining', () => { const expected = 'Hello world!'; it('matches if the received value does not contain the expected substring', () => { expect('How are you?').toEqual(expect.not.stringContaining(expected)); }); });
expect.not.stringMatching(string | regexp)
expect.not.stringMatching(string | regexp)
соответствует полученному значению, если оно не является строкой или если это строка, которая не соответствует ожидаемой строке или регулярному выражению.
Это противоположность expect.stringMatching
.
describe('not.stringMatching', () => { const expected = /Hello world!/; it('matches if the received value does not match the expected regex', () => { expect('How are you?').toEqual(expect.not.stringMatching(expected)); }); });
expect.objectContaining(object)
expect.objectContaining(object)
соответствует любому полученному объекту, который рекурсивно соответствует ожидаемым свойствам. То есть ожидаемый объект — это подмножество полученного объекта. Следовательно, он соответствует полученному объекту, который содержит свойства, присутствующие в ожидаемом объекте.
Вместо буквальных значений свойств в ожидаемом объекте вы можете использовать сопоставители, expect.anything()
и т. Д.
Например, предположим, что мы ожидаем, что функция 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)
expect.stringContaining(string)
соответствует полученному значению, если это строка, содержащая точную ожидаемую строку.
expect.stringMatching(string | regexp)
expect.stringMatching(string | 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. Последний добавленный модуль — это первый протестированный модуль.
import serializer from 'my-serializer-module'; expect.addSnapshotSerializer(serializer);
Если вы добавляете сериализатор моментальных снимков в отдельные тестовые файлы вместо добавления его в конфигурацию snapshotSerializers
:
- Вы делаете зависимость явной,а не неявной.
- Вы избегаете ограничений конфигурации, из-за которых вы можете выйти из приложения create-react-app .
См. Дополнительную информацию в разделе « Настройка Jest» .
.not
Если вы знаете, как что-то тестировать, .not
позволяет вам протестировать противоположное. Например, этот код проверяет, что лучший вкус La Croix — не кокос:
test('the best flavor is not coconut', () => { expect(bestLaCroixFlavor()).not.toBe('coconut'); });
.resolves
Используйте resolves
, чтобы развернуть значение выполненного обещания, чтобы можно было связать любой другой сопоставитель. Если обещание отклонено, утверждение не выполняется.
Например, этот код проверяет, разрешается ли обещание и что в результате получается значение 'lemon'
:
test('resolves to lemon', () => { return expect(Promise.resolve('lemon')).resolves.toBe('lemon'); });
Обратите внимание, что, поскольку вы все еще тестируете обещания, тест по-прежнему асинхронный. Следовательно, вам нужно будет указать Jest подождать , вернув развернутое утверждение.
В качестве альтернативы вы можете использовать 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
Используйте .rejects
, чтобы раскрыть причину отклоненного обещания, чтобы можно было связать любой другой сопоставитель. Если обещание выполнено, утверждение не выполняется.
Например, этот код проверяет, что обещание отклоняется по причине 'octopus'
:
test('rejects to octopus', () => { return expect(Promise.reject(new Error('octopus'))).rejects.toThrow( 'octopus', ); });
Обратите внимание, что, поскольку вы все еще тестируете обещания, тест по-прежнему асинхронный. Следовательно, вам нужно будет указать Jest подождать , вернув развернутое утверждение.
В качестве альтернативы вы можете использовать async/await
в сочетании с .rejects
.
test('rejects to octopus', async () => { await expect(Promise.reject(new Error('octopus'))).rejects.toThrow('octopus'); });
.toBe(value)
Используйте .toBe
для сравнения примитивных значений или для проверки ссылочной идентичности экземпляров объектов. Он вызывает Object.is
для сравнения значений, что даже лучше для тестирования, чем оператор строгого равенства ===
.
Например, этот код будет проверять некоторые свойства объекта can
:
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
.
Хотя сопоставитель .toBe
проверяет ссылочную идентичность, он сообщает о глубоком сравнении значений, если утверждение не выполняется. Если различия между свойствами не помогают понять, почему тест не проходит, особенно если отчет большой, то вы можете переместить сравнение в функцию expect
. Например, чтобы подтвердить, являются ли элементы одним и тем же экземпляром:
- перезаписать
expect(received).toBe(expected)
как ожидаемыйexpect(Object.is(received, expected)).toBe(true)
- переписать
expect(received).not.toBe(expected)
как ожидаемыйexpect(Object.is(received, expected)).toBe(false)
.toHaveBeenCalled()
Также под псевдонимом: .toBeCalled()
Используйте .toHaveBeenCalledWith
, чтобы убедиться, что фиктивная функция вызывается с определенными аргументами. Аргументы проверяются по тому же алгоритму, что .toEqual
.
Например, предположим, что у вас есть drinkAll(drink, flavour)
которая берет функцию drink
и применяет ее ко всем доступным напиткам. Возможно, вы захотите проверить, называют ли drink
'lemon'
, но не 'octopus'
, потому что вкус 'octopus'
действительно странный, и почему что-то должно быть со вкусом осьминога? Вы можете сделать это с помощью этого набора тестов:
function drinkAll(callback, flavour) { if (flavour !== 'octopus') { callback(flavour); } } describe('drinkAll', () => { test('drinks something lemon-flavoured', () => { const drink = jest.fn(); drinkAll(drink, 'lemon'); expect(drink).toHaveBeenCalled(); }); test('does not drink something octopus-flavoured', () => { const drink = jest.fn(); drinkAll(drink, 'octopus'); expect(drink).not.toHaveBeenCalled(); }); });
.toHaveBeenCalledTimes(number)
Также под псевдонимом: .toBeCalledTimes(number)
Используйте .toHaveBeenCalledTimes
, чтобы гарантировать, что фиктивная функция вызывается точное количество раз.
Например, предположим, что у вас есть drinkEach(drink, Array<flavor>)
которая принимает функцию drink
и применяет ее к массиву переданных напитков. Вы можете проверить, вызывалась ли функция питья точное количество раз. Вы можете сделать это с помощью этого набора тестов:
test('drinkEach drinks each drink', () => { const drink = jest.fn(); drinkEach(drink, ['lemon', 'octopus']); expect(drink).toHaveBeenCalledTimes(2); });
.toHaveBeenCalledWith(arg1, arg2, ...)
Также под псевдонимом: .toBeCalledWith()
Используйте .toHaveBeenCalledWith
, чтобы убедиться, что фиктивная функция вызывается с определенными аргументами. Аргументы проверяются по тому же алгоритму, что .toEqual
.
Например, предположим, что вы можете зарегистрировать напиток с помощью функции 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
функция, вы можете использовать .toHaveBeenLastCalledWith, чтобы проверить, с какими аргументами она вызывалась в последний раз. Например, предположим, что у вас есть applyToAllFlavors(f)
которая применяет f
к набору ароматов, и вы хотите, чтобы при ее вызове последним ароматом, с которым она работает, было 'mango'
. Ты можешь написать:
test('applying to all flavors does mango last', () => { const drink = jest.fn(); applyToAllFlavors(drink); expect(drink).toHaveBeenLastCalledWith('mango'); });
.toHaveBeenNthCalledWith(nthCall, arg1, arg2, ....)
Также под псевдонимом: .nthCalledWith(nthCall, arg1, arg2, ...)
Если у вас есть .toHaveBeenNthCalledWith
функция, вы можете использовать .toHaveBeenNthCalledWith, чтобы проверить, с какими аргументами она была вызвана. Например, предположим, что у вас есть drinkEach(drink, Array<flavor>)
которая применяет f
к набору ароматов, и вы хотите убедиться, что при ее вызове первым ароматом, с которым она работает, будет « 'lemon'
а второй — 'octopus'
. Ты можешь написать:
test('drinkEach drinks each drink', () => { const drink = jest.fn(); drinkEach(drink, ['lemon', 'octopus']); expect(drink).toHaveBeenNthCalledWith(1, 'lemon'); expect(drink).toHaveBeenNthCalledWith(2, 'octopus'); });
note
n-й аргумент должен быть целым положительным числом,начиная с 1.
.toHaveReturned()
Также под псевдонимом: .toReturn()
Если у вас есть .toHaveReturned
функция, вы можете использовать .toHaveReturned, чтобы проверить, что фиктивная функция успешно вернулась (т.е. не вызвала ошибку) хотя бы один раз. Например, предположим, что у вас есть ложный drink
который возвращает true
. Ты можешь написать:
test('drinks returns', () => { const drink = jest.fn(() => true); drink(); expect(drink).toHaveReturned(); });
.toHaveReturnedTimes(number)
Также под псевдонимом: .toReturnTimes(number)
Используйте .toHaveReturnedTimes
, чтобы гарантировать, что фиктивная функция успешно вернулась (т. Е. Не выдала ошибку) точное количество раз. Любые вызовы фиктивной функции, которые вызывают ошибку, не учитываются при подсчете количества возвращаемых функцией.
Например, предположим, что у вас есть drink
который возвращает true
. Ты можешь написать:
test('drink returns twice', () => { const drink = jest.fn(() => true); drink(); drink(); expect(drink).toHaveReturnedTimes(2); });
.toHaveReturnedWith(value)
Также под псевдонимом: .toReturnWith(value)
Используйте .toHaveReturnedWith
, чтобы гарантировать, что фиктивная функция вернула определенное значение.
Например, предположим, что у вас есть имитация drink
которая возвращает название напитка, который был выпит. Ты можешь написать:
test('drink returns La Croix', () => { const beverage = {name: 'La Croix'}; const drink = jest.fn(beverage => beverage.name); drink(beverage); expect(drink).toHaveReturnedWith('La Croix'); });
.toHaveLastReturnedWith(value)
Также под псевдонимом: .lastReturnedWith(value)
Используйте .toHaveLastReturnedWith
, чтобы проверить конкретное значение, которое в последний раз вернула фиктивная функция. Если последний вызов фиктивной функции вызвал ошибку, то этот сопоставитель завершится ошибкой независимо от того, какое значение вы указали в качестве ожидаемого возвращаемого значения.
Например, предположим, что у вас есть имитация drink
которая возвращает название напитка, который был выпит. Ты можешь написать:
test('drink returns La Croix (Orange) last', () => { const beverage1 = {name: 'La Croix (Lemon)'}; const beverage2 = {name: 'La Croix (Orange)'}; const drink = jest.fn(beverage => beverage.name); drink(beverage1); drink(beverage2); expect(drink).toHaveLastReturnedWith('La Croix (Orange)'); });
.toHaveNthReturnedWith(nthCall, value)
Также под псевдонимом: .nthReturnedWith(nthCall, value)
Используйте .toHaveNthReturnedWith
, чтобы проверить конкретное значение, которое фиктивная функция вернула для n-го вызова. Если n-й вызов фиктивной функции выдал ошибку, то этот сопоставитель завершится ошибкой независимо от того, какое значение вы указали в качестве ожидаемого возвращаемого значения.
Например, предположим, что у вас есть имитация drink
которая возвращает название напитка, который был выпит. Ты можешь написать:
test('drink returns expected nth calls', () => { const beverage1 = {name: 'La Croix (Lemon)'}; const beverage2 = {name: 'La Croix (Orange)'}; const drink = jest.fn(beverage => beverage.name); drink(beverage1); drink(beverage2); expect(drink).toHaveNthReturnedWith(1, 'La Croix (Lemon)'); expect(drink).toHaveNthReturnedWith(2, 'La Croix (Orange)'); });
note
n-й аргумент должен быть целым положительным числом,начиная с 1.
.toHaveLength(number)
Используйте .toHaveLength
, чтобы проверить, что у объекта есть свойство .length
и для него установлено определенное числовое значение.
Это особенно полезно для проверки размера массивов или строк.
expect([1, 2, 3]).toHaveLength(3); expect('abc').toHaveLength(3); expect('').not.toHaveLength(5);
.toHaveProperty(keyPath, value?)
Используйте .toHaveProperty
, чтобы проверить, существует ли свойство по keyPath
ссылке keyPath для объекта. Для проверки глубоко вложенных свойств в объекте вы можете использовать точечную нотацию или массив, содержащий keyPath для глубоких ссылок.
Вы можете предоставить необязательный аргумент value
для сравнения полученного значения свойства (рекурсивно для всех свойств экземпляров объекта, также известного как глубокое равенство, например сопоставление toEqual
).
В следующем примере содержится объект houseForSale
с вложенными свойствами. Мы используем toHaveProperty
для проверки существования и значений различных свойств в объекте.
const houseForSale = { bath: true, bedrooms: 4, kitchen: { amenities: ['oven', 'stove', 'washer'], area: 20, wallColor: 'white', 'nice.oven': true, }, livingroom: { amenities: [ { couch: [ ['large', {dimensions: [20, 20]}], ['small', {dimensions: [10, 10]}], ], }, ], }, 'ceiling.height': 2, }; 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'); expect(houseForSale).toHaveProperty(['kitchen', 'area'], 20); expect(houseForSale).toHaveProperty( ['kitchen', 'amenities'], ['oven', 'stove', 'washer'], ); expect(houseForSale).toHaveProperty(['kitchen', 'amenities', 0], 'oven'); expect(houseForSale).toHaveProperty( 'livingroom.amenities[0].couch[0][1].dimensions[0]', 20, ); expect(houseForSale).toHaveProperty(['kitchen', 'nice.oven']); expect(houseForSale).not.toHaveProperty(['kitchen', 'open']); expect(houseForSale).toHaveProperty(['ceiling.height'], 'tall'); });
.toBeCloseTo(number, numDigits?)
Используйте toBeCloseTo
для сравнения чисел с плавающей запятой для приблизительного равенства.
Необязательный аргумент numDigits
ограничивает количество проверяемых цифр после десятичной точки. Для значения по умолчанию 2
критерием теста является Math.abs(expected - received) < 0.005
(то есть 10 ** -2 / 2
).
Интуитивные сравнения равенства часто терпят неудачу,потому что арифметика десятичных (основание 10)значений часто имеет ошибки округления в двоичном представлении ограниченной точности (основание 2).Например,этот тест не работает:
test('adding works sanely with decimals', () => { expect(0.2 + 0.1).toBe(0.3); });
Это не удается, потому что в JavaScript 0.2 + 0.1
фактически 0.30000000000000004
.
Например,этот тест проходит с точностью до 5 цифр:
test('adding works sanely with decimals', () => { expect(0.2 + 0.1).toBeCloseTo(0.3, 5); });
Поскольку ошибки с плавающей запятой — это проблема, toBeCloseTo
решает toBeCloseTo , он не поддерживает большие целочисленные значения.
.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
или 0
, и ваш код все равно будет работать. Итак, если вы хотите проверить, нет ли ошибок после того, как выпили немного La Croix, вы можете написать:
test('drinking La Croix does not lead to errors', () => { drinkSomeLaCroix(); expect(getErrors()).toBeFalsy(); });
В JavaScript существует шесть ложных значений: false
, 0
, ''
, null
, undefined
и NaN
. Все остальное правда.
.toBeGreaterThan(number | bigint)
Используйте toBeGreaterThan
для сравнения received > expected
числовых или больших целочисленных значений. Например, проверьте, что ouncesPerCan()
возвращает значение более 10 унций:
test('ounces per can is more than 10', () => { expect(ouncesPerCan()).toBeGreaterThan(10); });
.toBeGreaterThanOrEqual(number | bigint)
Используйте toBeGreaterThanOrEqual
для сравнения received >= expected
числовых или больших целочисленных значений. Например, проверьте, что ouncesPerCan()
возвращает значение не менее 12 унций:
test('ounces per can is at least 12', () => { expect(ouncesPerCan()).toBeGreaterThanOrEqual(12); });
.toBeLessThan(number | bigint)
Используйте toBeLessThan
для сравнения received < expected
числовых или больших целочисленных значений. Например, проверьте, что ouncesPerCan()
возвращает значение менее 20 унций:
test('ounces per can is less than 20', () => { expect(ouncesPerCan()).toBeLessThan(20); });
.toBeLessThanOrEqual(number | bigint)
Используйте toBeLessThanOrEqual
для сравнения received <= expected
числовых или больших целочисленных значений. Например, проверьте, что 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)
но сообщения об ошибках немного приятнее. Поэтому используйте .toBeNull()
если хотите проверить, что что-то имеет значение null.
function bloop() { return null; } test('bloop returns null', () => { expect(bloop()).toBeNull(); });
.toBeTruthy()
Используйте .toBeTruthy
, если вам все равно, что такое значение, и вы хотите убедиться, что значение истинно в логическом контексте. Например, допустим, у вас есть код приложения, который выглядит так:
drinkSomeLaCroix(); if (thirstInfo()) { drinkMoreLaCroix(); }
Вам может быть все равно, что возвращает thirstInfo
, в частности — он может вернуть true
или сложный объект, и ваш код все равно будет работать. Так что если вы хотите проверить , что thirstInfo
будет truthy выпив некоторое La Croix, вы могли бы написать:
test('drinking La Croix leads to having thirst info', () => { drinkSomeLaCroix(); expect(thirstInfo()).toBeTruthy(); });
В JavaScript существует шесть ложных значений: false
, 0
, ''
, 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
прямо в коде.
.toBeNaN()
Используйте .toBeNaN
при проверке значения NaN
.
test('passes when value is NaN', () => { expect(NaN).toBeNaN(); expect(1).not.toBeNaN(); });
.toContain(item)
Используйте .toContain
, если хотите проверить, находится ли элемент в массиве. Для тестирования элементов в массиве используется ===
, строгая проверка на равенство. .toContain
также может проверять, является ли строка подстрокой другой строки.
Например, если getAllFlavors()
возвращает массив вкусов и вы хотите быть уверены, что там есть lime
, вы можете написать:
test('the flavor list contains lime', () => { expect(getAllFlavors()).toContain('lime'); });
Этот матчер также принимает другие итерации,такие как строки,множества,списки узлов и коллекции HTML.
.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
для рекурсивного сравнения всех свойств экземпляров объекта (также известного как «глубокое» равенство). Он вызывает Object.is
для сравнения примитивных значений, что даже лучше для тестирования, чем оператор строгого равенства ===
.
Например, .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); }); });
tip
.toEqual
не будет выполнять глубокую проверку на равенство для двух ошибок. Только свойство message
объекта Error считается равным. Для проверки на наличие ошибок рекомендуется использовать сопоставитель .toThrow
.
Если различия между свойствами не помогают понять, почему тест не проходит, особенно если отчет большой, то вы можете перенести сравнение в функцию expect
. Например, используйте метод equals
класса Buffer
, чтобы проверить, содержат ли буферы одно и то же содержимое:
- перезаписать
expect(received).toEqual(expected)
как ожидаемыйexpect(received.equals(expected)).toBe(true)
- переписать
expect(received).not.toEqual(expected)
как ожидаемыйexpect(received.equals(expected)).toBe(false)
.toMatch(regexp | string)
Используйте .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
, чтобы проверить, соответствует ли объект JavaScript подмножеству свойств объекта. Он сопоставляет полученные объекты со свойствами, которых нет в ожидаемом объекте.
Вы также можете передать массив объектов, и в этом случае метод вернет true, только если каждый объект в полученном массиве совпадает (в смысле toMatchObject
, описанном выше) с соответствующим объектом в ожидаемом массиве. Это полезно, если вы хотите проверить совпадение двух массивов по количеству элементов, в отличие от arrayContaining
, который позволяет добавлять дополнительные элементы в полученный массив.
Вы можете сравнивать свойства со значениями или с матчами.
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', () => { test('the number of elements must match exactly', () => { expect([{foo: 'bar'}, {baz: 1}]).toMatchObject([{foo: 'bar'}, {baz: 1}]); }); 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}, ]); }); });
.toMatchSnapshot(propertyMatchers?, hint?)
Это гарантирует, что значение соответствует самому последнему снимку. Ознакомьтесь с руководством по тестированию снимков для получения дополнительной информации.
Вы можете предоставить необязательный аргумент объекта propertyMatchers
, который имеет асимметричные сопоставители как значения подмножества ожидаемых свойств, если полученное значение будет экземпляром объекта . Это похоже на toMatchObject
с гибкими критериями для подмножества свойств, за которым следует тест снимка в качестве точных критериев для остальных свойств.
Вы можете указать необязательный аргумент строки hint
который будет добавлен к имени теста. Хотя Jest всегда добавляет число в конце имени снимки, короткие описательные подсказки могут быть более полезными , чем числа , чтобы различать несколько снимков в едином it
или test
блок. Jest сортирует снимки по имени в соответствующем файле .snap
.
.toMatchInlineSnapshot(propertyMatchers?, inlineSnapshot)
Обеспечивает соответствие значения последнему снимку.
Вы можете предоставить необязательный аргумент объекта propertyMatchers
, который имеет асимметричные сопоставители как значения подмножества ожидаемых свойств, если полученное значение будет экземпляром объекта . Это похоже на toMatchObject
с гибкими критериями для подмножества свойств, за которым следует тест снимка в качестве точных критериев для остальных свойств.
Jest добавляет строковый аргумент inlineSnapshot
к сопоставителю в тестовом файле (вместо внешнего файла .snap
) при первом запуске теста.
Ознакомьтесь с разделом « Встроенные снимки» для получения дополнительной информации.
.toStrictEqual(value)
Используйте .toStrictEqual
, чтобы проверить, что объекты имеют одинаковые типы и структуру.
Отличия от .toEqual
:
- Проверяются ключи с
undefined
свойствами. например,{a: undefined, b: 2}
не соответствует{b: 2}
при использовании.toStrictEqual
. - Проверяется разреженность массива. например,
[, 1]
не соответствует[undefined, 1]
при использовании.toStrictEqual
. - Проверяется соответствие типов объектов. например, экземпляр класса с полями
a
иb
не будет равняться буквальному объекту с полямиa
иb
.
class LaCroix { constructor(flavor) { this.flavor = flavor; } } describe('the La Croix cans on my desk', () => { test('are not semantically the same', () => { expect(new LaCroix('lemon')).toEqual({flavor: 'lemon'}); expect(new LaCroix('lemon')).not.toStrictEqual({flavor: 'lemon'}); }); });
.toThrow(error?)
Также под псевдонимом: .toThrowError(error?)
Используйте .toThrow
, чтобы проверить, вызывает ли функция при ее вызове. Например, если мы хотим проверить, что drinkFlavor('octopus')
бросает, потому что вкус осьминога слишком отвратителен для питья, мы могли бы написать:
test('throws on octopus', () => { expect(() => { drinkFlavor('octopus'); }).toThrow(); });
tip
Вы должны обернуть код в функцию,иначе ошибка не будет поймана и утверждение не пройдет.
Вы можете предоставить необязательный аргумент для проверки того,что конкретная ошибка выбрасывается:
- регулярное выражение: сообщение об ошибке соответствует шаблону
- строка: сообщение об ошибке включает подстроку
- объект ошибки: сообщение об ошибке равно свойству сообщения объекта
- класс ошибки: объект ошибки является экземпляром класса
Например, предположим, что 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/); expect(drinkOctopus).toThrowError('yuck'); expect(drinkOctopus).toThrowError(/^yuck, octopus flavor$/); expect(drinkOctopus).toThrowError(new Error('yuck, octopus flavor')); expect(drinkOctopus).toThrowError(DisgustingFlavorError); });
.toThrowErrorMatchingSnapshot(hint?)
Используйте .toThrowErrorMatchingSnapshot
, чтобы проверить, что функция выдает ошибку, соответствующую самому последнему снимку при ее вызове.
Вы можете указать необязательный аргумент строки hint
который будет добавлен к имени теста. Хотя Jest всегда добавляет число в конце имени снимки, короткие описательные подсказки могут быть более полезными , чем числа , чтобы различать несколько снимков в едином it
или test
блок. Jest сортирует снимки по имени в соответствующем файле .snap
.
Например, предположим, что у вас есть функция 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 для получения дополнительной информации о тестировании моментальных снимков.
.toThrowErrorMatchingInlineSnapshot(inlineSnapshot)
Используйте .toThrowErrorMatchingInlineSnapshot
, чтобы проверить, что функция выдает ошибку, соответствующую самому последнему снимку, когда она вызывается.
Jest добавляет строковый аргумент inlineSnapshot
к сопоставителю в тестовом файле (вместо внешнего файла .snap
) при первом запуске теста.
Ознакомьтесь с разделом « Встроенные снимки» для получения дополнительной информации.
Jest
29.0
-
Environment Variables
Jest устанавливает следующие переменные среды: Установите «тест», если это уже не что-то другое.
-
Манекен ES6 Класс
Jest можно использовать для имитации классов ES6, которые импортируются в файлы, которые вы хотите протестировать.
-
Jest Community
Сообщество вокруг Jest усердно работает над тем, чтобы сделать тестирование еще лучше.
-
Объект шутки
Объект jest автоматически находится в области видимости в каждом тестовом файле.