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
7,7402 gold badges12 silver badges23 bronze badges
10
It is a little bit weird, but it works and IMHO is good readable:
it('should throw Error with message 'UNKNOWN ERROR' when no parameters were passed', () => {
try {
throwError();
// Fail test if above expression doesn't throw anything.
expect(true).toBe(false);
} catch (e) {
expect(e.message).toBe("UNKNOWN ERROR");
}
});
The Catch
block catches your exception, and then you can test on your raised Error
. Strange expect(true).toBe(false);
is needed to fail your test if the expected Error
will be not thrown. Otherwise, this line is never reachable (Error
should be raised before them).
@Kenny Body suggested a better solution which improve a code quality if you use expect.assertions()
:
it('should throw Error with message 'UNKNOWN ERROR' when no parameters were passed', () => {
expect.assertions(1);
try {
throwError();
} catch (e) {
expect(e.message).toBe("UNKNOWN ERROR");
}
});
See the original answer with more explanations: How to test the type of a thrown exception in Jest
EDIT 2022:
To use this approach and not trigger no-conditional-expect
rule (if you’re using eslint-plugin-jest
), documentation of this rule suggest to use error wrapper:
class NoErrorThrownError extends Error {}
const getError = async <TError>(call: () => unknown): Promise<TError> => {
try {
await call();
throw new NoErrorThrownError();
} catch (error: unknown) {
return error as TError;
}
};
describe('when the http request fails', () => {
it('includes the status code in the error', async () => {
const error = await getError(async () => makeRequest(url));
// check that the returned error wasn't that no error was thrown
expect(error).not.toBeInstanceOf(NoErrorThrownError);
expect(error).toHaveProperty('statusCode', 404);
});
});
See: no-conditional-expect
docs
answered Mar 27, 2018 at 12:31
Paweł BB DrozdPaweł BB Drozd
4,3734 gold badges20 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,2574 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,0198 silver badges5 bronze badges
5
I manage to combine some answers and end up with this:
it('should throw', async () => {
await expect(service.methodName('some@email.com', 'unknown')).rejects.toThrow(
HttpException,
);
});
answered Jul 28, 2021 at 8:37
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
9191 gold badge8 silver badges10 bronze badges
2
Further to Peter Danis’ post, I just wanted to emphasize the part of his solution involving «[passing] a function into expect(function).toThrow(blank or type of error)».
In Jest, when you test for a case where an error should be thrown, within your expect() wrapping of the function under testing, you need to provide one additional arrow function wrapping layer in order for it to work. I.e.
Wrong (but most people’s logical approach):
expect(functionUnderTesting();).toThrow(ErrorTypeOrErrorMessage);
Right:
expect(() => { functionUnderTesting(); }).toThrow(ErrorTypeOrErrorMessage);
It’s very strange, but it should make the testing run successfully.
answered May 24, 2020 at 7:05
AdrianAdrian
1,58510 silver badges6 bronze badges
3
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,6162 gold badges25 silver badges23 bronze badges
2
You must wrap the code of the function that you are expecting in another arrow function, otherwise the error will not be caught and the assertion will fail.
the function you want to test :
const testThrowingError = () => {
throw new Error();
};
the test:
describe("error function should Throw Error", () => {
expect(() =>testThrowingError()).toThrowError();
});
resource:
https://jestjs.io/docs/expect#tothrowerror
answered Jul 4, 2022 at 13:50
Safi HabhabSafi Habhab
95110 silver badges17 bronze badges
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
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
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,07114 silver badges27 bronze badges
I have successfully used this
await expect(
async () => await apiCalls()
).rejects.toThrow();
answered Feb 28, 2022 at 20:00
Liu HantaoLiu Hantao
6101 gold badge9 silver badges19 bronze badges
Jest has a method, toThrow(error)
, to test that a function throws when it is called.
So, in your case you should call it so:
expect(t).toThrowError(TypeError);
The documentation.
answered Sep 4, 2017 at 18:49
alexmacalexmac
18.9k7 gold badges57 silver badges67 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,4816 gold badges36 silver badges50 bronze badges
I ended up writing a convenience method for our test-utils library
/**
* Utility method to test for a specific error class and message in Jest
* @param {fn, expectedErrorClass, expectedErrorMessage }
* @example failTest({
fn: () => {
return new MyObject({
param: 'stuff'
})
},
expectedErrorClass: MyError,
expectedErrorMessage: 'stuff not yet implemented'
})
*/
failTest: ({ fn, expectedErrorClass, expectedErrorMessage }) => {
try {
fn()
expect(true).toBeFalsy()
} catch (err) {
let isExpectedErr = err instanceof expectedErrorClass
expect(isExpectedErr).toBeTruthy()
expect(err.message).toBe(expectedErrorMessage)
}
}
answered Jun 20, 2019 at 8:31
kpollockkpollock
3,8797 gold badges42 silver badges61 bronze badges
2
There is also an easier way to assert against the error message. The beauty of this method is that you don’t need to reconstruct the error object or have the full error message. As long as your error contains part of the error message we can assume it is of the correct type. i.e
const printOnlyString = (str) => {
if(typeof str !== "string"){
throw Error("I can only print strings ${typeof str) given");
}
else {
console.log(str);
}
}
expect(() => printOnlyString(123)).toThrow(/can only print strings/)
answered Oct 21, 2022 at 16:08
Yasin YaqoobiYasin Yaqoobi
1,8783 gold badges27 silver badges37 bronze badges
1
To test whether a function throws a specific error message with a specific type of error, you can use Jest’s toThrow()
matcher
function myFunction() {
throw new TypeError('Something went wrong');
}
describe('myFunction', () => {
it('should throw a TypeError with a specific error message', () => {
expect(myFunction).toThrow(TypeError);
expect(myFunction).toThrow(/Something went wrong/);
//noted: this way will invoke the myFunction twice
expect(myFunction).toBeCalledTimes(2)
});
});
If you use expect(myFunction).toThrow(new TypeError("Something went wrong")
, it only checks the error message rather than the error type, which does not meet the test purpose.
answered Apr 28 at 2:45
Kaiwen LuoKaiwen Luo
3503 silver badges9 bronze badges
A good way is to create custom error classes and mock them. Then you can assert whatever you want.
MessedUpError.ts
type SomeCrazyErrorObject = {
[key: string]: unknown,
}
class MessedUpError extends Error {
private customErrorData: SomeCrazyErrorObject = {};
constructor(err?: string, data?: SomeCrazyErrorObject) {
super(err || 'You messed up');
Object.entries(data ?? {}).forEach(([Key, value]) => {
this.customErrorData[Key] = value;
});
Error.captureStackTrace(this, this.constructor);
}
logMe() {
console.log(this.customErrorData);
}
}
export default MessedUpError;
messedUpError.test.ts
import MessedUpError from './MessedUpError';
jest.mock('./MessedUpError', () => jest.fn().mockImplementation((...args: any[]) => ({
constructor: args,
log: () => {},
})));
type MessedUpErrorContructorParams = Expand<typeof MessedUpError['prototype']>
const MessedUpErrorMock = MessedUpError as unknown as jest.Mock<MessedUpError, [MessedUpErrorContructorParams]>;
const serverErrorContructorCall = (i = 0) => ({
message: MessedUpErrorMock.mock.calls[i][0],
...MessedUpErrorMock.mock.calls[i][1] || {},
});
beforeEach(() => {
MessedUpErrorMock.mockClear();
});
test('Should throw', async () => {
try {
await someFunctionThatShouldThrowMessedUpError();
} catch {} finally {
expect(MessedUpErrorMock).toHaveBeenCalledTimes(1);
const constructorParams = serverErrorContructorCall();
expect(constructorParams).toHaveProperty('message', 'You messed up');
expect(constructorParams).toHaveProperty('customErrorProperty', 'someValue');
}
});
The assertions always go inside the finally
clause. This way it will always be asserted. Even if the test does not throw any errors.
answered Apr 1, 2022 at 13:49
Omar OmeiriOmar Omeiri
1,4381 gold badge17 silver badges31 bronze badges
Try:
expect(t).rejects.toThrow()
answered May 16, 2019 at 16:37
2
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);
The code
Let’s consider a simple function that checks for equality of two passwords, and it throws an error when the first one is not provided:
export default function samePasswordsValidator(password, otherPassword) {
if (!password) {
throw new Error("no password given");
}
return password === otherPassword;
}
Try-catch idiom (bad)
When testing the code that throws exceptions, one immediately comes up with the idea of using the try-catch
idiom in the test code:
it('throws an error when first argument is `null`', () => {
try {
samePasswordsValidator(null, "bar");
} catch (error) {
expect(error.message).toBe("no password given");
}
});
Generally speaking, this is not the best approach. The test passes when the first argument is null
as expected. But when the code is about to change and the exception won’t be thrown anymore the test still passes. So, the code change won’t be detected by the test.
Try-catch idiom (better)
To overcome that issue, one could expect that actual assertion will be executed and fail the test if it does not happen. This can be done pretty easily with expect.assertions
which verifies that a certain number of assertions are called during a test:
it('throws an error when first argument is `null`', () => {
expect.assertions(1);
try {
samePasswordsValidator(null, "bar");
} catch (error) {
expect(error.message).toBe("no password given");
}
});
Now, when no exception is thrown, the test fails:
Error: expect.assertions(1)
Expected one assertion to be called but received zero assertion calls.
toThrow
assertions (best)
To make the code even more expressive a built-in toThrow
matcher can be used:
it('throws an error when first argument is `null`', () => {
expect(() => samePasswordsValidator(null, "bar")).toThrow("no password given");
});
And again, when no exception is thrown, Jest informs us clearly about it with a failed test:
Error: expect(received).toThrow(expected)
Expected substring: "no password given"
Received function did not throw
Note that toThrow
matcher can be used to not only check the error message, but also the exact type of the error:
it('throws an error when first argument is `null`', () => {
expect(() => samePasswordsValidator(null, "bar")).toThrow(Error);
expect(() => samePasswordsValidator(null, "bar")).toThrow(new Error("no password given"));
});
See also
- Testing promise rejection in JavaScript with Jest
- Jest Vanilla JS Starter
- Different ways of handling exceptions in JUnit. Which one to choose?
When you’re writing tests, you often need to check that values meet certain conditions. expect
gives you access to a number of «matchers» that let you validate different things.
Methods #
expect(value)
expect.extend(matchers)
expect.anything()
expect.any(constructor)
expect.arrayContaining(array)
expect.assertions(number)
expect.hasAssertions()
expect.objectContaining(object)
expect.stringContaining(string)
expect.stringMatching(regexp)
expect.addSnapshotSerializer(serializer)
.not
.resolves
.rejects
.toBe(value)
.toHaveBeenCalled()
.toHaveBeenCalledTimes(number)
.toHaveBeenCalledWith(arg1, arg2, ...)
.toHaveBeenLastCalledWith(arg1, arg2, ...)
.toBeCloseTo(number, numDigits)
.toBeDefined()
.toBeFalsy()
.toBeGreaterThan(number)
.toBeGreaterThanOrEqual(number)
.toBeLessThan(number)
.toBeLessThanOrEqual(number)
.toBeInstanceOf(Class)
.toBeNull()
.toBeTruthy()
.toBeUndefined()
.toContain(item)
.toContainEqual(item)
.toEqual(value)
.toHaveLength(number)
.toMatch(regexpOrString)
.toMatchObject(object)
.toHaveProperty(keyPath, value)
.toMatchSnapshot(optionalString)
.toThrow(error)
.toThrowErrorMatchingSnapshot()
Reference #
expect(value)
#
The expect
function is used every time you want to test a value. You will rarely call expect
by itself. Instead, you will use expect
along with a «matcher» function to assert something about a value.
It’s easier to understand this with an example. Let’s say you have a method bestLaCroixFlavor()
which is supposed to return the string 'grapefruit'
.
Here’s how you would test that:
test('the best flavor is grapefruit', () => { expect(bestLaCroixFlavor()).toBe('grapefruit'); });
In this case, toBe
is the matcher function. There are a lot of different matcher functions, documented below, to help you test different things.
The argument to expect
should be the value that your code produces, and any argument to the matcher should be the correct value. If you mix them up, your tests will still work, but the error messages on failing tests will look strange.
expect.extend(matchers)
#
You can use expect.extend
to add your own matchers to Jest. For example, let’s say that you’re testing a number theory library and you’re frequently asserting that numbers are divisible by other numbers. You could abstract that into a toBeDivisibleBy
matcher:
expect.extend({ toBeDivisibleBy(received, argument) { const pass = (received % argument == 0); if (pass) { return { message: () => ( `expected ${received} not to be divisible by ${argument}` ), pass: true, }; } else { return { message: () => (`expected ${received} to be divisible by ${argument}`), pass: false, }; } }, }); test('even and odd numbers', () => { expect(100).toBeDivisibleBy(2); expect(101).not.toBeDivisibleBy(2); });
Matchers should return an object with two keys. pass
indicates whether there was a match or not, and message
provides a function with no arguments that returns an error message in case of failure. Thus, when pass
is false, message
should return the error message for when expect(x).yourMatcher()
fails. And when pass
is true, message
should return the error message for when expect(x).not.yourMatcher()
fails.
These helper functions can be found on this
inside a custom matcher:
this.isNot
#
A boolean to let you know this matcher was called with the negated .not
modifier allowing you to flip your assertion.
this.equals(a, b)
#
This is a deep-equality function that will return true
if two objects have the same values (recursively).
this.utils
#
There are a number of helpful tools exposed on this.utils
primarily consisting of the exports from jest-matcher-utils
.
The most useful ones are matcherHint
, printExpected
and printReceived
to format the error messages nicely. For example, take a look at the implementation for the toBe
matcher:
const diff = require('jest-diff'); expect.extend({ toBe(received, expected) { const pass = received === expected; const message = pass ? () => this.utils.matcherHint('.not.toBe') + 'nn' + `Expected value to not be (using ===):n` + ` ${this.utils.printExpected(expected)}n` + `Received:n` + ` ${this.utils.printReceived(received)}` : () => { const diffString = diff(expected, received, { expand: this.expand, }); return this.utils.matcherHint('.toBe') + 'nn' + `Expected value to be (using ===):n` + ` ${this.utils.printExpected(expected)}n` + `Received:n` + ` ${this.utils.printReceived(received)}` + (diffString ? `nnDifference:nn${diffString}` : ''); }; return {actual: received, message, pass}; }, });
This will print something like this:
expect(received).toBe(expected) Expected value to be (using ===): "banana" Received: "apple"
When an assertion fails, the error message should give as much signal as necessary to the user so they can resolve their issue quickly. You should craft a precise failure message to make sure users of your custom assertions have a good developer experience.
expect.anything()
#
expect.anything()
matches anything but null
or undefined
. You can use it inside toEqual
or toBeCalledWith
instead of a literal value. For example, if you want to check that a mock function is called with a non-null argument:
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)
matches anything that was created with the given constructor. You can use it inside toEqual
or toBeCalledWith
instead of a literal value. For example, if you want to check that a mock function is called with a number:
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)
matches a received array which contains all of the elements in the expected array. That is, the expected array is a subset of the received array. Therefore, it matches a received array which contains elements that are not in the expected array.
You can use it instead of a literal value:
- in
toEqual
ortoBeCalledWith
- to match a property in
objectContaining
ortoMatchObject
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)
verifies that a certain number of assertions are called during a test. This is often useful when testing asynchronous code, in order to make sure that assertions in a callback actually got called.
For example, let’s say that we have a function doAsync
that receives two callbacks callback1
and callback2
, it will asynchronously call both of them in an unknown order. We can test this with:
test('doAsync calls both callbacks', () => { expect.assertions(2); function callback1(data) { expect(data).toBeTruthy(); } function callback2(data) { expect(data).toBeTruthy(); } doAsync(callback1, callback2); });
The expect.assertions(2)
call ensures that both callbacks actually get called.
expect.hasAssertions()
#
expect.hasAssertions()
verifies that at least one assertion is called during a test. This is often useful when testing asynchronous code, in order to make sure that assertions in a callback actually got called.
For example, let’s say that we have a few functions that all deal with state. prepareState
calls a callback with a state object, validateState
runs on that state object, and waitOnState
returns a promise that waits until all prepareState
callbacks complete. We can test this with:
test('prepareState prepares a valid state', () => { expect.hasAssertions(); prepareState(state => { expect(validateState(state)).toBeTruthy(); }); return waitOnState(); });
The expect.hasAssertions()
call ensures that the prepareState
callback actually gets called.
expect.objectContaining(object)
#
expect.objectContaining(object)
matches any received object that recursively matches the expected properties. That is, the expected object is a subset of the received object. Therefore, it matches a received object which contains properties that are not in the expected object.
Instead of literal property values in the expected object, you can use matchers, expect.anything()
, and so on.
For example, let’s say that we expect an onPress
function to be called with an Event
object, and all we need to verify is that the event has event.x
and event.y
properties. We can do that with:
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)
#
available in Jest 19.0.0+ #
expect.stringContaining(string)
matches any received string that contains the exact expected string.
expect.stringMatching(regexp)
#
expect.stringMatching(regexp)
matches any received string that matches the expected regexp.
You can use it instead of a literal value:
- in
toEqual
ortoBeCalledWith
- to match an element in
arrayContaining
- to match a property in
objectContaining
ortoMatchObject
This example also shows how you can nest multiple asymmetric matchers, with expect.stringMatching
inside the 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)
#
You can call expect.addSnapshotSerializer
to add a module that formats application-specific data structures.
For an individual test file, an added module precedes any modules from snapshotSerializers
configuration, which precede the default snapshot serializers for built-in JavaScript types and for React elements. The last module added is the first module tested.
import serializer from 'my-serializer-module'; expect.addSnapshotSerializer(serializer);
If you add a snapshot serializer in individual test files instead of to adding it to snapshotSerializers
configuration:
- You make the dependency explicit instead of implicit.
- You avoid limits to configuration that might cause you to eject from create-react-app.
See configuring Jest for more information.
.not
#
If you know how to test something, .not
lets you test its opposite. For example, this code tests that the best La Croix flavor is not coconut:
test('the best flavor is not coconut', () => { expect(bestLaCroixFlavor()).not.toBe('coconut'); });
.resolves
#
available in Jest 20.0.0+ #
Use resolves
to unwrap the value of a fulfilled promise so any other matcher can be chained. If the promise is rejected the assertion fails.
For example, this code tests that the promise resolves and that the resulting value is 'lemon'
:
test('resolves to lemon', () => { return expect(Promise.resolve('lemon')).resolves.toBe('lemon'); });
Alternatively, you can use async/await
in combination with .resolves
:
test('resolves to lemon', async () => { await expect(Promise.resolve('lemon')).resolves.toBe('lemon'); await expect(Promise.resolve('lemon')).resolves.not.toBe('octopus'); });
.rejects
#
available in Jest 20.0.0+ #
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.
For example, this code tests that the promise rejects with a reason:
test('fetchData() rejects to be error', () => { return expect(Promise.reject('octopus')).rejects.toBeDefined(); });
Alternatively, you can use async/await
in combination with .rejects
.
Moreover, this code tests that the returned reason includes ‘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
just checks that a value is what you expect. It uses ===
to check
strict equality.
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'); }); });
Don’t use toBe
with floating-point numbers. For example, due to rounding, in JavaScript 0.2 + 0.1
is not strictly equal to 0.3
. If you have floating point numbers, try .toBeCloseTo
instead.
.toHaveBeenCalled()
#
Also under the alias: .toBeCalled()
Use .toHaveBeenCalled
to ensure that a mock function got called.
For example, let’s say you have a drinkAll(drink, flavor)
function that takes a drink
function and applies it to all available beverages. You might want to check that drink
gets called for 'lemon'
, but not for 'octopus'
, because 'octopus'
flavor is really weird and why would anything be octopus-flavored? You can do that with this test suite:
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)
#
Use .toHaveBeenCalledTimes
to ensure that a mock function got called exact number of times.
For example, let’s say you have a drinkEach(drink, Array<flavor>)
function that takes a drink
function and applies it to array of passed beverages. You might want to check that drink function was called exact number of times. You can do that with this test suite:
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()
Use .toHaveBeenCalledWith
to ensure that a mock function was called with specific arguments.
For example, let’s say that you can register a beverage with a register
function, and applyToAll(f)
should apply the function f
to all registered beverages. To make sure this works, you could write:
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, ...)
#
Also under the alias: .lastCalledWith(arg1, arg2, ...)
If you have a mock function, you can use .toHaveBeenLastCalledWith
to test what arguments it was last called with. For example, let’s say you have a applyToAllFlavors(f)
function that applies f
to a bunch of flavors, and you want to ensure that when you call it, the last flavor it operates on is 'mango'
. You can write:
test('applying to all flavors does mango last', () => { const drink = jest.fn(); applyToAllFlavors(drink); expect(drink).toHaveBeenLastCalledWith('mango'); });
.toBeCloseTo(number, numDigits)
#
Using exact equality with floating point numbers is a bad idea. Rounding means that intuitive things fail. For example, this test fails:
test('adding works sanely with simple decimals', () => { expect(0.2 + 0.1).toBe(0.3); });
It fails because in JavaScript, 0.2 + 0.1
is actually 0.30000000000000004
. Sorry.
Instead, use .toBeCloseTo
. Use numDigits
to control how many digits after the decimal point to check. For example, if you want to be sure that 0.2 + 0.1
is equal to 0.3
with a precision of 5 decimal digits, you can use this test:
test('adding works sanely with simple decimals', () => { expect(0.2 + 0.1).toBeCloseTo(0.3, 5); });
The default for numDigits
is 2, which has proved to be a good default in most cases.
.toBeDefined()
#
Use .toBeDefined
to check that a variable is not undefined. For example, if you just want to check that a function fetchNewFlavorIdea()
returns something, you can write:
test('there is a new flavor idea', () => { expect(fetchNewFlavorIdea()).toBeDefined(); });
You could write expect(fetchNewFlavorIdea()).not.toBe(undefined)
, but it’s better practice to avoid referring to undefined
directly in your code.
.toBeFalsy()
#
Use .toBeFalsy
when you don’t care what a value is, you just want to ensure a value is false in a boolean context. For example, let’s say you have some application code that looks like:
drinkSomeLaCroix(); if (!getErrors()) { drinkMoreLaCroix(); }
You may not care what getErrors
returns, specifically — it might return false
, null
, or 0
, and your code would still work. So if you want to test there are no errors after drinking some La Croix, you could write:
test('drinking La Croix does not lead to errors', () => { drinkSomeLaCroix(); expect(getErrors()).toBeFalsy(); });
In JavaScript, there are six falsy values: false
, 0
, ''
, null
, undefined
, and NaN
. Everything else is truthy.
.toBeGreaterThan(number)
#
To compare floating point numbers, you can use toBeGreaterThan
. For example, if you want to test that ouncesPerCan()
returns a value of more than 10 ounces, write:
test('ounces per can is more than 10', () => { expect(ouncesPerCan()).toBeGreaterThan(10); });
.toBeGreaterThanOrEqual(number)
#
To compare floating point numbers, you can use toBeGreaterThanOrEqual
. For example, if you want to test that ouncesPerCan()
returns a value of at least 12 ounces, write:
test('ounces per can is at least 12', () => { expect(ouncesPerCan()).toBeGreaterThanOrEqual(12); });
.toBeLessThan(number)
#
To compare floating point numbers, you can use toBeLessThan
. For example, if you want to test that ouncesPerCan()
returns a value of less than 20 ounces, write:
test('ounces per can is less than 20', () => { expect(ouncesPerCan()).toBeLessThan(20); });
.toBeLessThanOrEqual(number)
#
To compare floating point numbers, you can use toBeLessThanOrEqual
. For example, if you want to test that ouncesPerCan()
returns a value of at most 12 ounces, write:
test('ounces per can is at most 12', () => { expect(ouncesPerCan()).toBeLessThanOrEqual(12); });
.toBeInstanceOf(Class)
#
Use .toBeInstanceOf(Class)
to check that an object is an instance of a class. This matcher uses instanceof
underneath.
class A {} expect(new A()).toBeInstanceOf(A); expect(() => {}).toBeInstanceOf(Function); expect(new A()).toBeInstanceOf(Function);
.toBeNull()
#
.toBeNull()
is the same as .toBe(null)
but the error messages are a bit nicer. So use .toBeNull()
when you want to check that something is null.
function bloop() { return null; } test('bloop returns null', () => { expect(bloop()).toBeNull(); });
.toBeTruthy()
#
Use .toBeTruthy
when you don’t care what a value is, you just want to ensure a value is true in a boolean context. For example, let’s say you have some application code that looks like:
drinkSomeLaCroix(); if (thirstInfo()) { drinkMoreLaCroix(); }
You may not care what thirstInfo
returns, specifically — it might return true
or a complex object, and your code would still work. So if you just want to test that thirstInfo
will be truthy after drinking some La Croix, you could write:
test('drinking La Croix leads to having thirst info', () => { drinkSomeLaCroix(); expect(thirstInfo()).toBeTruthy(); });
In JavaScript, there are six falsy values: false
, 0
, ''
, null
, undefined
, and NaN
. Everything else is truthy.
.toBeUndefined()
#
Use .toBeUndefined
to check that a variable is undefined. For example, if you want to check that a function bestDrinkForFlavor(flavor)
returns undefined
for the 'octopus'
flavor, because there is no good octopus-flavored drink:
test('the best drink for octopus flavor is undefined', () => { expect(bestDrinkForFlavor('octopus')).toBeUndefined(); });
You could write expect(bestDrinkForFlavor('octopus')).toBe(undefined)
, but it’s better practice to avoid referring to undefined
directly in your code.
.toContain(item)
#
Use .toContain
when you want to check that an item is in a list. For testing the items in the list, this uses ===
, a strict equality check.
For example, if getAllFlavors()
returns a list of flavors and you want to be sure that lime
is in there, you can write:
test('the flavor list contains lime', () => { expect(getAllFlavors()).toContain('lime'); });
.toContainEqual(item)
#
Use .toContainEqual
when you want to check that an item is in a list.
For testing the items in the list, this matcher recursively checks the equality of all fields, rather than checking for object identity.
describe('my beverage', () => { test('is delicious and not sour', () => { const myBeverage = {delicious: true, sour: false}; expect(myBeverages()).toContainEqual(myBeverage); }); });
.toEqual(value)
#
Use .toEqual
when you want to check that two objects have the same value. This matcher recursively checks the equality of all fields, rather than checking for object identity—this is also known as «deep equal». For example, toEqual
and toBe
behave differently in this test suite, so all the tests pass:
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); }); });
Note:
.toEqual
won’t perform a deep equality check for two errors. Only themessage
property of an Error is considered for equality. It is recommended to use the.toThrow
matcher for testing against errors.
.toHaveLength(number)
#
Use .toHaveLength
to check that an object has a .length
property and it is set to a certain numeric value.
This is especially useful for checking arrays or strings size.
expect([1, 2, 3]).toHaveLength(3); expect('abc').toHaveLength(3); expect('').not.toHaveLength(5);
.toMatch(regexpOrString)
#
Use .toMatch
to check that a string matches a regular expression.
For example, you might not know what exactly essayOnTheBestFlavor()
returns, but you know it’s a really long string, and the substring grapefruit
should be in there somewhere. You can test this with:
describe('an essay on the best flavor', () => { test('mentions grapefruit', () => { expect(essayOnTheBestFlavor()).toMatch(/grapefruit/); expect(essayOnTheBestFlavor()).toMatch(new RegExp('grapefruit')); }); });
This matcher also accepts a string, which it will try to match:
describe('grapefruits are healthy', () => { test('grapefruits are a fruit', () => { expect('grapefruits').toMatch('fruit'); }); });
.toMatchObject(object)
#
Use .toMatchObject
to check that a JavaScript object matches a subset of the properties of an object. 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)
#
Use .toHaveProperty
to check if property at provided reference keyPath
exists for an object.
For checking deeply nested properties in an object use dot notation for deep references.
Optionally, you can provide a value
to check if it’s equal to the value present at keyPath
on the target object. This matcher uses ‘deep equality’ (like toEqual()
) and recursively checks the equality of all fields.
The following example contains a houseForSale
object with nested properties. We are using toHaveProperty
to check for the existence and values of various properties in the object.
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)
#
This ensures that a value matches the most recent snapshot. Check out the Snapshot Testing guide for more information.
You can also specify an optional snapshot name. Otherwise, the name is inferred from the test.
Note: While snapshot testing is most commonly used with React components, any serializable value can be used as a snapshot.
.toThrow(error)
#
Also under the alias: .toThrowError(error)
Use .toThrow
to test that a function throws when it is called. For example, if we want to test that drinkFlavor('octopus')
throws, because octopus flavor is too disgusting to drink, we could write:
test('throws on octopus', () => { expect(() => { drinkFlavor('octopus'); }).toThrow(); });
If you want to test that a specific error gets thrown, you can provide an argument to toThrow
. The argument can be a string for the error message, a class for the error, or a regex that should match the error. For example, let’s say that drinkFlavor
is coded like this:
function drinkFlavor(flavor) { if (flavor == 'octopus') { throw new DisgustingFlavorError('yuck, octopus flavor'); } }
We could test this error gets thrown in several ways:
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. For example, let’s say you have a drinkFlavor
function that throws whenever the flavor is 'octopus'
, and is coded like this:
function drinkFlavor(flavor) { if (flavor == 'octopus') { throw new DisgustingFlavorError('yuck, octopus flavor'); } }
The test for this function will look this way:
test('throws on octopus', () => { function drinkOctopus() { drinkFlavor('octopus'); } expect(drinkOctopus).toThrowErrorMatchingSnapshot(); });
And it will generate the following snapshot:
exports[`drinking flavors throws on octopus 1`] = `"yuck, octopus flavor"`;
Check out React Tree Snapshot Testing for more information on snapshot testing.
Whenever you are looking to test an error thrown by a function in Jest, you want to pass the function to the expect
, rather than invoking the function. Take a look at the following examples:
const functionWithError = param => {
throw new Error()
}
it('should throw an error', () => {
expect(functionWithError).toThrow(Error)
})
Copied to clipboard!
We have a mock function and we want to test whether it throws the error we are expecting. We can do this by simply passing the function to the expect without actually invoking it, and calling the toThrow
method on it with the passed error.
But what if you have to call the function, for example, to provide parameters? In this case, you can wrap the function into an anonymous function:
// 🟢 Do
expect(() => functionWithError()).toThrow(Error)
// 🔴 Don’t
expect(functionWithError()).toThrow(Error)
expect(functionWithError('param')).toThrow(Error)
Copied to clipboard!
Notice that if you try to call the function directly inside the expect
, it will fail the test as the error is not caught and the assertion will fail. You can also test other types of errors by passing the correct error to toThrow
:
expect(functionWithError()).toThrow(EvalError)
expect(functionWithError()).toThrow(RangeError)
expect(functionWithError()).toThrow(ReferenceError)
expect(functionWithError()).toThrow(SyntaxError)
expect(functionWithError()).toThrow(TypeError)
expect(functionWithError()).toThrow(URIError)
expect(functionWithError()).toThrow(AggregateError)
Pass the correct type of error to test different types
Copied to clipboard!
Lastly, if you would like to test the error message itself, toThrow
also accepts a string so you can test both the type and message:
const functionWithError = () => {
throw new TypeError('Custom Error')
}
it('should throw an error', () => {
expect(functionWithError).toThrow(TypeError)
expect(functionWithError).toThrow('Custom Error')
})
Copied to clipboard!
How to Mock process.env in JestUnit testing environment-specific parts in your applicationLearn how you can properly mock environment variables in your Jest tests to correctly test environment-specific parts in your application.
Когда вы пишете тесты, вам часто нужно проверить, соответствуют ли значения определенным условиям. expect
дает вам доступ к ряду «сопоставителей», которые позволяют вам проверять разные вещи.
Чтобы узнать о дополнительных сопоставителях 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) + 'nn' + `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) + 'nn' + (diffString && diffString.includes('- Expect') ? `Difference:nn${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 автоматически находится в области видимости в каждом тестовом файле.
На чтение 4 мин. Просмотров 23 Опубликовано 30.10.2022
Содержание
- Введение
- Общие матчеры
- 1. Истинность
- 2. Числа
- 2. Строки
- 3. Массивы и итерационные таблицы
- 4. Исключения
Введение
Jest использует «matchers», чтобы позволить вам проверять значения различными способами.
Большая часть информации в этой части взята из документации по Jest.
Общие матчеры
Самый простой способ проверить значение — это точное равенство.
test('two plus two is four', () => {
expect(2 + 2).toBe(4);
});
Войти в полноэкранный режим Выйти из полноэкранного режима
В этом коде expect(2 + 2) возвращает объект «expectation». Обычно с этими объектами ожиданий не нужно делать ничего особенного, кроме вызова на них матчеров. В этом коде .toBe(4) является матчером. Когда Jest запускается, он отслеживает все неудачные матчики, чтобы можно было вывести красивые сообщения об ошибках.
toBe
использует Object для проверки точного равенства. Если вы хотите проверить значение объекта, используйте вместо него toEqual
:
test('object assignment', () => {
const data = {one: 1};
data['two'] = 2;
expect(data).toEqual({one: 1, two: 2});
});
Войти в полноэкранный режим Выйти из полноэкранного режима
toEqual
рекурсивно проверяет каждое поле объекта или массива.
Вы также можете проверить противоположность матчера:
test('adding positive numbers is not zero', () => {
for (let a = 1; a < 10; a++) {
for (let b = 1; b < 10; b++) {
expect(a + b).not.toBe(0);
}
}
});
Войти в полноэкранный режим Выйти из полноэкранного режима
1. Истинность
В тестах иногда требуется различать понятия undefined, null и false. Jest содержит помощники, которые позволяют вам четко определить, что вы хотите.
test('null', () => {
const n = null;
expect(n).toBeNull();
expect(n).toBeDefined();
expect(n).not.toBeUndefined();
expect(n).not.toBeTruthy();
expect(n).toBeFalsy();
});
test('zero', () => {
const z = 0;
expect(z).not.toBeNull();
expect(z).toBeDefined();
expect(z).not.toBeUndefined();
expect(z).not.toBeTruthy();
expect(z).toBeFalsy();
});
Войти в полноэкранный режим Выйти из полноэкранного режима
Примечание: используйте матчер, который наиболее точно соответствует тому, что вы хотите, чтобы делал ваш код.
2. Числа
jest предоставляет различные матчеры для сравнения чисел.
Пример:
test('two plus two', () => {
const value = 2 + 2;
expect(value).toBeGreaterThan(3);
expect(value).toBeGreaterThanOrEqual(3.5);
expect(value).toBeLessThan(5);
expect(value).toBeLessThanOrEqual(4.5);
// toBe and toEqual are equivalent for numbers
expect(value).toBe(4);
expect(value).toEqual(4);
});
Войти в полноэкранный режим Выход из полноэкранного режима
Для равенства чисел с плавающей точкой используйте toBeCloseTo
вместо toEqual
, потому что вы не хотите, чтобы тест зависел от крошечной ошибки округления, чтобы понять эту ошибку, нажмите здесь.
test('adding floating point numbers', () => {
const value = 0.1 + 0.2;
//expect(value).toBe(0.3); This won't work because of rounding error
expect(value).toBeCloseTo(0.3); // This works.
});
Вход в полноэкранный режим Выйдите из полноэкранного режима
2. Строки
jest предоставляет возможность проверки строк на соответствие регулярным выражениям с помощью toMatch
:
test('there is no I in team', () => {
expect('team').not.toMatch(/I/);
});
test('but there is a "stop" in Christoph', () => {
expect('Christoph').toMatch(/stop/);
});
Войти в полноэкранный режим Выйти из полноэкранного режима
3. Массивы и итерационные таблицы
Вы можете проверить, содержит ли массив или итерируемая таблица определенный элемент, используя toContain
:
const shoppingList = [
'diapers',
'kleenex',
'trash bags',
'paper towels',
'milk',
];
test('the shopping list has milk on it', () => {
expect(shoppingList).toContain('milk');
expect(new Set(shoppingList)).toContain('milk');
});
Войти в полноэкранный режим Выйти из полноэкранного режима
4. Исключения
Если вы хотите проверить, выбрасывает ли определенная функция ошибку при вызове, jest предоставляет матчер toThrow
.
function compileAndroidCode() {
throw new Error('you are using the wrong JDK');
}
test('compiling android goes as expected', () => {
expect(() => compileAndroidCode()).toThrow();
expect(() => compileAndroidCode()).toThrow(Error);
// You can also use the exact error message or a regexp
expect(() => compileAndroidCode()).toThrow('you are using the wrong JDK');
expect(() => compileAndroidCode()).toThrow(/JDK/);
});
Вход в полноэкранный режим Выход из полноэкранного режима
Примечание: функция, которая выбрасывает исключение, должна быть вызвана внутри обертывающей функции, иначе утверждение toThrow
будет неудачным.
Изучать новые концепции и делиться ими с другими — моя страсть, и мне доставляет удовольствие помогать и вдохновлять людей. Если у вас есть вопросы, не стесняйтесь, обращайтесь!
Подключайтесь ко мне в Twitter, Linkedin и GitHub.
Как вы знаете, каждому есть куда совершенствоваться, поэтому ваши предложения будут приняты с благодарностью. И я буду рада (❤️) узнать что-то новое.