Skip to main content
Version: 29.7

期望

当你编写测试时,你经常需要检查值是否满足某些条件。expect 使你可以访问许多 "matchers",让你验证不同的事物。

¥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.

提示

有关 Jest 社区维护的其他 Jest 匹配器,请查看 jest-extended

¥For additional Jest matchers maintained by the Jest Community check out jest-extended.

信息

仅当你显式导入 Jest API 时,此页面中的 TypeScript 示例才会按照文档说明的方式工作:

¥The TypeScript examples from this page will only work as documented if you explicitly import Jest APIs:

import {expect, jest, test} from '@jest/globals';

有关如何使用 TypeScript 设置 Jest 的详细信息,请参阅 入门 指南。

¥Consult the Getting Started guide for details on how to setup Jest with TypeScript.

参考

¥Reference


期望

¥Expect

expect(value)

每次要测试值时都会使用 expect 函数。你很少会单独调用 expect。相反,你将使用 expect 和 "matcher" 函数来断言某个值的某些内容。

¥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.

通过一个例子更容易理解这一点。假设你有一个方法 bestLaCroixFlavor(),它应该返回字符串 'grapefruit'。你可以通过以下方式进行测试:

¥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');
});

在本例中,toBe 是匹配器函数。下面记录了许多不同的匹配器函数,可以帮助你测试不同的东西。

¥In this case, toBe is the matcher function. There are a lot of different matcher functions, documented below, to help you test different things.

expect 的参数应该是代码生成的值,并且匹配器的任何参数都应该是正确的值。如果你把它们混合起来,你的测试仍然可以工作,但是失败的测试的错误消息看起来会很奇怪。

¥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.

修饰符

¥Modifiers

.not

如果你知道如何测试某些东西,.not 可以让你测试它的反面。例如,此代码测试最好的 La Croix 风味不是椰子:

¥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

使用 resolves 来解开已履行 promise 的值,以便可以链接任何其他匹配器。如果 promise 被拒绝,则断言失败。

¥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.

例如,此代码测试 Promise 是否解析以及结果值是否为 'lemon'

¥For example, this code tests that the promise resolves and that the resulting value is 'lemon':

test('resolves to lemon', () => {
// make sure to add a return statement
return expect(Promise.resolve('lemon')).resolves.toBe('lemon');
});
注意

由于你仍在测试 Promise,因此测试仍然是异步的。因此,你需要通过返回未封装的断言来 让杰斯特稍等一下

¥Since you are still testing promises, the test is still asynchronous. Hence, you will need to tell Jest to wait by returning the unwrapped assertion.

或者,你可以将 async/await.resolves 结合使用:

¥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

使用 .rejects 来解开被拒绝的 Promise 的原因,以便可以链接任何其他匹配器。如果 promise 得到履行,则断言失败。

¥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.

例如,此代码测试 Promise 是否因原因 'octopus' 而拒绝:

¥For example, this code tests that the promise rejects with reason 'octopus':

test('rejects to octopus', () => {
// make sure to add a return statement
return expect(Promise.reject(new Error('octopus'))).rejects.toThrow(
'octopus',
);
});
注意

由于你仍在测试 Promise,因此测试仍然是异步的。因此,你需要通过返回未封装的断言来 让杰斯特稍等一下

¥Since you are still testing promises, the test is still asynchronous. Hence, you will need to tell Jest to wait by returning the unwrapped assertion.

或者,你可以将 async/await.rejects 结合使用。

¥Alternatively, you can use async/await in combination with .rejects.

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

匹配器

¥Matchers

.toBe(value)

使用 .toBe 比较原始值或检查对象实例的引用标识。它调用 Object.is 来比较值,这比 === 严格相等运算符更适合测试。

¥Use .toBe to compare primitive values or to check referential identity of object instances. It calls Object.is to compare values, which is even better for testing than === strict equality operator.

例如,此代码将验证 can 对象的一些属性:

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

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

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

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

不要将 .toBe 与浮点数一起使用。例如,由于四舍五入的原因,JavaScript 中的 0.2 + 0.1 并不严格等于 0.3。如果你有浮点数,请尝试使用 .toBeCloseTo

¥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.

尽管 .toBe 匹配器会检查引用身份,但如果断言失败,它会报告值的深度比较。如果属性之间的差异不能帮助你理解测试失败的原因,特别是在报告很大的情况下,那么你可以将比较移至 expect 函数中。例如,断言元素是否是同一实例:

¥Although the .toBe matcher checks referential identity, it reports a deep comparison of values if the assertion fails. If differences between properties do not help you to understand why a test fails, especially if the report is large, then you might move the comparison into the expect function. For example, to assert whether or not elements are the same instance:

  • expect(received).toBe(expected) 重写为 expect(Object.is(received, expected)).toBe(true)

    ¥rewrite expect(received).toBe(expected) as expect(Object.is(received, expected)).toBe(true)

  • expect(received).not.toBe(expected) 重写为 expect(Object.is(received, expected)).toBe(false)

    ¥rewrite expect(received).not.toBe(expected) as expect(Object.is(received, expected)).toBe(false)

.toHaveBeenCalled()

也在别名下:.toBeCalled()

¥Also under the alias: .toBeCalled()

使用 .toHaveBeenCalled 确保调用了模拟函数。

¥Use .toHaveBeenCalled to ensure that a mock function was called.

例如,假设你有一个 drinkAll(drink, flavour) 函数,它接受 drink 函数并将其应用于所有可用的饮料。你可能想检查 drink 是否被称为 'lemon',但不是 'octopus',因为 'octopus' 的味道真的很奇怪,为什么会有章鱼味的东西?你可以使用此测试套件来做到这一点:

¥For example, let's say you have a drinkAll(drink, flavour) 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' flavour is really weird and why would anything be octopus-flavoured? You can do that with this test suite:

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)

¥Also under the alias: .toBeCalledTimes(number)

使用 .toHaveBeenCalledTimes 确保模拟函数被调用的确切次数。

¥Use .toHaveBeenCalledTimes to ensure that a mock function got called exact number of times.

例如,假设你有一个 drinkEach(drink, Array<flavor>) 函数,它接受 drink 函数并将其应用于传递的饮料数组。你可能想要检查 Drink 函数被调用的确切次数。你可以使用此测试套件来做到这一点:

¥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, ...)

也在别名下:.toBeCalledWith()

¥Also under the alias: .toBeCalledWith()

使用 .toHaveBeenCalledWith 确保使用特定参数调用模拟函数。使用 .toEqual 使用的相同算法检查参数。

¥Use .toHaveBeenCalledWith to ensure that a mock function was called with specific arguments. The arguments are checked with the same algorithm that .toEqual uses.

例如,假设你可以使用 register 函数注册饮料,而 applyToAll(f) 应该将函数 f 应用于所有已注册的饮料。为了确保它有效,你可以这样写:

¥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, ...)

也在别名下:.lastCalledWith(arg1, arg2, ...)

¥Also under the alias: .lastCalledWith(arg1, arg2, ...)

如果你有模拟函数,则可以使用 .toHaveBeenLastCalledWith 来测试上次调用它时使用的参数。例如,假设你有一个 applyToAllFlavors(f) 函数,它将 f 应用于一堆风味,并且你希望确保当你调用它时,它操作的最后一个风味是 'mango'。你可以写:

¥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');
});

.toHaveBeenNthCalledWith(nthCall, arg1, arg2, ....)

也在别名下:.nthCalledWith(nthCall, arg1, arg2, ...)

¥Also under the alias: .nthCalledWith(nthCall, arg1, arg2, ...)

如果你有模拟函数,则可以使用 .toHaveBeenNthCalledWith 来测试第 n 次调用它的参数。例如,假设你有一个 drinkEach(drink, Array<flavor>) 函数,它将 f 应用于一堆风味,并且你希望确保在调用它时,它操作的第一个风味是 'lemon',第二个是 'octopus'。你可以写:

¥If you have a mock function, you can use .toHaveBeenNthCalledWith to test what arguments it was nth called with. For example, let's say you have a drinkEach(drink, Array<flavor>) function that applies f to a bunch of flavors, and you want to ensure that when you call it, the first flavor it operates on is 'lemon' and the second one is 'octopus'. You can write:

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

第 n 个参数必须是从 1 开始的正整数。

¥The nth argument must be positive integer starting from 1.

.toHaveReturned()

也在别名下:.toReturn()

¥Also under the alias: .toReturn()

如果你有一个模拟函数,你可以使用 .toHaveReturned 来测试该模拟函数是否至少成功返回一次(即,没有抛出错误)。例如,假设你有一个返回 true 的模拟 drink。你可以写:

¥If you have a mock function, you can use .toHaveReturned to test that the mock function successfully returned (i.e., did not throw an error) at least one time. For example, let's say you have a mock drink that returns true. You can write:

test('drinks returns', () => {
const drink = jest.fn(() => true);

drink();

expect(drink).toHaveReturned();
});

.toHaveReturnedTimes(number)

也在别名下:.toReturnTimes(number)

¥Also under the alias: .toReturnTimes(number)

使用 .toHaveReturnedTimes 确保模拟函数成功返回(即,没有抛出错误)准确的次数。任何抛出错误的模拟函数调用都不会计入该函数返回的次数。

¥Use .toHaveReturnedTimes to ensure that a mock function returned successfully (i.e., did not throw an error) an exact number of times. Any calls to the mock function that throw an error are not counted toward the number of times the function returned.

例如,假设你有一个返回 true 的模拟 drink。你可以写:

¥For example, let's say you have a mock drink that returns true. You can write:

test('drink returns twice', () => {
const drink = jest.fn(() => true);

drink();
drink();

expect(drink).toHaveReturnedTimes(2);
});

.toHaveReturnedWith(value)

也在别名下:.toReturnWith(value)

¥Also under the alias: .toReturnWith(value)

使用 .toHaveReturnedWith 确保模拟函数返回特定值。

¥Use .toHaveReturnedWith to ensure that a mock function returned a specific value.

例如,假设你有一个模拟 drink,它返回所喝饮料的名称。你可以写:

¥For example, let's say you have a mock drink that returns the name of the beverage that was consumed. You can write:

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)

¥Also under the alias: .lastReturnedWith(value)

使用 .toHaveLastReturnedWith 测试模拟函数最后返回的具体值。如果对模拟函数的最后一次调用引发了错误,则无论你提供什么值作为预期返回值,此匹配器都将失败。

¥Use .toHaveLastReturnedWith to test the specific value that a mock function last returned. If the last call to the mock function threw an error, then this matcher will fail no matter what value you provided as the expected return value.

例如,假设你有一个模拟 drink,它返回所喝饮料的名称。你可以写:

¥For example, let's say you have a mock drink that returns the name of the beverage that was consumed. You can write:

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)

¥Also under the alias: .nthReturnedWith(nthCall, value)

使用 .toHaveNthReturnedWith 测试模拟函数第 n 次调用返回的特定值。如果对模拟函数的第 n 次调用抛出错误,则无论你提供什么值作为预期返回值,此匹配器都将失败。

¥Use .toHaveNthReturnedWith to test the specific value that a mock function returned for the nth call. If the nth call to the mock function threw an error, then this matcher will fail no matter what value you provided as the expected return value.

例如,假设你有一个模拟 drink,它返回所喝饮料的名称。你可以写:

¥For example, let's say you have a mock drink that returns the name of the beverage that was consumed. You can write:

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)');
});
注意

第 n 个参数必须是从 1 开始的正整数。

¥The nth argument must be positive integer starting from 1.

.toHaveLength(number)

使用 .toHaveLength 检查对象是否具有 .length 属性并且该属性已设置为某个数值。

¥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);

.toHaveProperty(keyPath, value?)

使用 .toHaveProperty 检查所提供的引用 keyPath 处的属性是否存在于某个对象。要检查对象中的深度嵌套属性,你可以使用 点符号 或包含深度引用的 keyPath 的数组。

¥Use .toHaveProperty to check if property at provided reference keyPath exists for an object. For checking deeply nested properties in an object you may use dot notation or an array containing the keyPath for deep references.

你可以提供可选的 value 参数来比较接收到的属性值(递归地比较对象实例的所有属性,也称为深度相等,如 toEqual 匹配器)。

¥You can provide an optional value argument to compare the received property value (recursively for all properties of object instances, also known as deep equality, like the toEqual matcher).

以下示例包含具有嵌套属性的 houseForSale 对象。我们使用 toHaveProperty 来检查对象中各种属性是否存在及其值。

¥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.

// Object containing house features to be tested
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', () => {
// Example Referencing
expect(houseForSale).toHaveProperty('bath');
expect(houseForSale).toHaveProperty('bedrooms', 4);

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

// Deep referencing using dot notation
expect(houseForSale).toHaveProperty('kitchen.area', 20);
expect(houseForSale).toHaveProperty('kitchen.amenities', [
'oven',
'stove',
'washer',
]);

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

// Deep referencing using an array containing the keyPath
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']);

// Referencing keys with dot in the key itself
expect(houseForSale).toHaveProperty(['ceiling.height'], 'tall');
});

.toBeCloseTo(number, numDigits?)

使用 toBeCloseTo 比较浮点数是否近似相等。

¥Use toBeCloseTo to compare floating point numbers for approximate equality.

可选的 numDigits 参数限制小数点后要检查的位数。对于默认值 2,测试标准为 Math.abs(expected - received) < 0.005(即 10 ** -2 / 2)。

¥The optional numDigits argument limits the number of digits to check after the decimal point. For the default value 2, the test criterion is Math.abs(expected - received) < 0.005 (that is, 10 ** -2 / 2).

直观的相等比较通常会失败,因为十进制(以 10 为基数)值的算术在有限精度的二进制(以 2 为基数)表示中通常会出现舍入误差。例如,此测试失败:

¥Intuitive equality comparisons often fail, because arithmetic on decimal (base 10) values often have rounding errors in limited precision binary (base 2) representation. For example, this test fails:

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

它失败了,因为在 JavaScript 中,0.2 + 0.1 实际上是 0.30000000000000004

¥It fails because in JavaScript, 0.2 + 0.1 is actually 0.30000000000000004.

例如,此测试以 5 位精度通过:

¥For example, this test passes with a precision of 5 digits:

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

因为浮点错误是 toBeCloseTo 解决的问题,所以它不支持大整数值。

¥Because floating point errors are the problem that toBeCloseTo solves, it does not support big integer values.

.toBeDefined()

使用 .toBeDefined 检查变量是否未定义。例如,如果你想检查函数 fetchNewFlavorIdea() 是否返回某些内容,你可以编写:

¥Use .toBeDefined to check that a variable is not undefined. For example, if you want to check that a function fetchNewFlavorIdea() returns something, you can write:

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

你可以编写 expect(fetchNewFlavorIdea()).not.toBe(undefined),但更好的做法是避免在代码中直接引用 undefined

¥You could write expect(fetchNewFlavorIdea()).not.toBe(undefined), but it's better practice to avoid referring to undefined directly in your code.

.toBeFalsy()

当你不关心值是什么并且希望确保布尔上下文中的值为 false 时,请使用 .toBeFalsy。例如,假设你有一些如下所示的应用代码:

¥Use .toBeFalsy when you don't care what a value is and you 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();
}

你可能不关心 getErrors 返回什么,特别是 - 它可能会返回 falsenull0,并且你的代码仍然可以工作。所以如果你想测试喝了一些 La Croix 后没有错误,你可以这样写:

¥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();
});

在 JavaScript 中,有六个假值:false0''nullundefinedNaN。其他一切都是真实的。

¥In JavaScript, there are six falsy values: false, 0, '', null, undefined, and NaN. Everything else is truthy.

.toBeGreaterThan(number | bigint)

使用 toBeGreaterThan 比较 received > expected 的数字或大整数值。例如,测试 ouncesPerCan() 返回的值是否大于 10 盎司:

¥Use toBeGreaterThan to compare received > expected for number or big integer values. For example, test that ouncesPerCan() returns a value of more than 10 ounces:

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

.toBeGreaterThanOrEqual(number | bigint)

使用 toBeGreaterThanOrEqual 比较 received >= expected 的数字或大整数值。例如,测试 ouncesPerCan() 返回的值至少为 12 盎司:

¥Use toBeGreaterThanOrEqual to compare received >= expected for number or big integer values. For example, test that ouncesPerCan() returns a value of at least 12 ounces:

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

.toBeLessThan(number | bigint)

使用 toBeLessThan 比较 received < expected 的数字或大整数值。例如,测试 ouncesPerCan() 返回的值是否小于 20 盎司:

¥Use toBeLessThan to compare received < expected for number or big integer values. For example, test that ouncesPerCan() returns a value of less than 20 ounces:

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

.toBeLessThanOrEqual(number | bigint)

使用 toBeLessThanOrEqual 比较 received <= expected 的数字或大整数值。例如,测试 ouncesPerCan() 返回的值最多为 12 盎司:

¥Use toBeLessThanOrEqual to compare received <= expected for number or big integer values. For example, test that ouncesPerCan() returns a value of at most 12 ounces:

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

.toBeInstanceOf(Class)

使用 .toBeInstanceOf(Class) 检查对象是否是类的实例。该匹配器在下面使用 instanceof

¥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); // throws

.toBeNull()

.toBeNull().toBe(null) 相同,但错误消息更好一些。因此,当你想检查某些内容是否为空时,请使用 .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()

当你不关心值是什么并且希望确保值在布尔上下文中为 true 时,请使用 .toBeTruthy。例如,假设你有一些如下所示的应用代码:

¥Use .toBeTruthy when you don't care what a value is and you 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();
}

你可能不关心 thirstInfo 返回什么,特别是 - 它可能会返回 true 或复杂的对象,并且你的代码仍然可以工作。因此,如果你想在喝了一些 La Croix 后测试 thirstInfo 是否真实,你可以这样写:

¥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 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();
});

在 JavaScript 中,有六个假值:false0''nullundefinedNaN。其他一切都是真实的。

¥In JavaScript, there are six falsy values: false, 0, '', null, undefined, and NaN. Everything else is truthy.

.toBeUndefined()

使用 .toBeUndefined 检查变量是否未定义。例如,如果你想检查函数 bestDrinkForFlavor(flavor) 是否为 'octopus' 口味返回 undefined,因为没有好的章鱼味饮料:

¥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();
});

你可以编写 expect(bestDrinkForFlavor('octopus')).toBe(undefined),但更好的做法是避免在代码中直接引用 undefined

¥You could write expect(bestDrinkForFlavor('octopus')).toBe(undefined), but it's better practice to avoid referring to undefined directly in your code.

.toBeNaN()

当检查值是 NaN 时使用 .toBeNaN

¥Use .toBeNaN when checking a value is NaN.

test('passes when value is NaN', () => {
expect(NaN).toBeNaN();
expect(1).not.toBeNaN();
});

.toContain(item)

当你想要检查某个项目是否在数组中时,请使用 .toContain。为了测试数组中的项目,这使用了 ===,即严格的相等检查。.toContain 还可以检查一个字符串是否是另一个字符串的子字符串。

¥Use .toContain when you want to check that an item is in an array. For testing the items in the array, this uses ===, a strict equality check. .toContain can also check whether a string is a substring of another string.

例如,如果 getAllFlavors() 返回一个口味数组,并且你想确保 lime 位于其中,则可以编写:

¥For example, if getAllFlavors() returns an array 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');
});

该匹配器还接受其他可迭代对象,例如字符串、集合、节点列表和 HTML 集合。

¥This matcher also accepts others iterables such as strings, sets, node lists and HTML collections.

.toContainEqual(item)

当你想要检查数组中是否包含具有特定结构和值的项目时,请使用 .toContainEqual。为了测试数组中的项目,此匹配器递归地检查所有字段的相等性,而不是检查对象标识。

¥Use .toContainEqual when you want to check that an item with a specific structure and values is contained in an array. For testing the items in the array, 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)

使用 .toEqual 递归比较对象实例的所有属性(也称为 "deep" 相等性)。它调用 Object.is 来比较原始值,这比 === 严格相等运算符更适合测试。

¥Use .toEqual to compare recursively all properties of object instances (also known as "deep" equality). It calls Object.is to compare primitive values, which is even better for testing than === strict equality operator.

例如,.toEqual.toBe 在此测试套件中的行为不同,因此所有测试都通过:

¥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);
});
});
提示

toEqual 忽略具有 undefined 属性、undefined 数组项、数组稀疏性或对象类型不匹配的对象键。要考虑这些,请改用 .toStrictEqual

¥toEqual ignores object keys with undefined properties, undefined array items, array sparseness, or object type mismatch. To take these into account use .toStrictEqual instead.

信息

.toEqual 不会对两个错误执行深度相等检查。仅错误的 message 属性被视为相等。建议使用 .toThrow 匹配器来测试错误。

¥.toEqual won't perform a deep equality check for two errors. Only the message property of an Error is considered for equality. It is recommended to use the .toThrow matcher for testing against errors.

如果属性之间的差异不能帮助你理解测试失败的原因,特别是在报告很大的情况下,那么你可以将比较移至 expect 函数中。例如,使用 Buffer 类的 equals 方法来断言缓冲区是否包含相同的内容:

¥If differences between properties do not help you to understand why a test fails, especially if the report is large, then you might move the comparison into the expect function. For example, use equals method of Buffer class to assert whether or not buffers contain the same content:

  • expect(received).toEqual(expected) 重写为 expect(received.equals(expected)).toBe(true)

    ¥rewrite expect(received).toEqual(expected) as expect(received.equals(expected)).toBe(true)

  • expect(received).not.toEqual(expected) 重写为 expect(received.equals(expected)).toBe(false)

    ¥rewrite expect(received).not.toEqual(expected) as expect(received.equals(expected)).toBe(false)

.toMatch(regexp | string)

使用 .toMatch 检查字符串是否与正则表达式匹配。

¥Use .toMatch to check that a string matches a regular expression.

例如,你可能不知道 essayOnTheBestFlavor() 到底返回什么,但你知道它是一个非常长的字符串,并且子字符串 grapefruit 应该在其中的某个位置。你可以使用以下方法进行测试:

¥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)

使用 .toMatchObject 检查 JavaScript 对象是否与对象属性的子集匹配。它将接收的对象与预期对象中不存在的属性进行匹配。

¥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.

你还可以传递对象数组,在这种情况下,仅当接收到的数组中的每个对象与预期数组中的相应对象匹配(在上述 toMatchObject 意义上)时,该方法才会返回 true。如果你想检查两个数组的元素数量是否匹配,这非常有用,这与 arrayContaining 不同,后者允许在接收的数组中包含额外的元素。

¥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', () => {
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?)

这可确保值与最新快照匹配。查看 快照测试指南 了解更多信息。

¥This ensures that a value matches the most recent snapshot. Check out the Snapshot Testing guide for more information.

你可以提供可选的 propertyMatchers 对象参数,如果接收到的值是对象实例,则该参数将非对称匹配器作为预期属性子集的值。它就像 toMatchObject,对属性子集具有灵活的标准,然后进行快照测试作为其余属性的精确标准。

¥You can provide an optional propertyMatchers object argument, which has asymmetric matchers as values of a subset of expected properties, if the received value will be an object instance. It is like toMatchObject with flexible criteria for a subset of properties, followed by a snapshot test as exact criteria for the rest of the properties.

你可以提供附加到测试名称的可选 hint 字符串参数。尽管 Jest 总是在快照名称末尾附加一个数字,但简短的描述性提示可能比数字更有用,可以区分单个 ittest 块中的多个快照。Jest 按相应 .snap 文件中的名称对快照进行排序。

¥You can provide an optional hint string argument that is appended to the test name. Although Jest always appends a number at the end of a snapshot name, short descriptive hints might be more useful than numbers to differentiate multiple snapshots in a single it or test block. Jest sorts snapshots by name in the corresponding .snap file.

.toMatchInlineSnapshot(propertyMatchers?, inlineSnapshot)

确保值与最新快照匹配。

¥Ensures that a value matches the most recent snapshot.

你可以提供可选的 propertyMatchers 对象参数,如果接收到的值是对象实例,则该参数将非对称匹配器作为预期属性子集的值。它就像 toMatchObject,对属性子集具有灵活的标准,然后进行快照测试作为其余属性的精确标准。

¥You can provide an optional propertyMatchers object argument, which has asymmetric matchers as values of a subset of expected properties, if the received value will be an object instance. It is like toMatchObject with flexible criteria for a subset of properties, followed by a snapshot test as exact criteria for the rest of the properties.

第一次运行测试时,Jest 将 inlineSnapshot 字符串参数添加到测试文件中的匹配器(而不是外部 .snap 文件)。

¥Jest adds the inlineSnapshot string argument to the matcher in the test file (instead of an external .snap file) the first time that the test runs.

查看 内联快照 部分以获取更多信息。

¥Check out the section on Inline Snapshots for more info.

.toStrictEqual(value)

使用 .toStrictEqual 来测试对象是否具有相同的结构和类型。

¥Use .toStrictEqual to test that objects have the same structure and type.

.toEqual 的区别:

¥Differences from .toEqual:

  • 检查具有 undefined 属性的键,例如 {a: undefined, b: 2} 不会等于 {b: 2}

    ¥keys with undefined properties are checked, e.g. {a: undefined, b: 2} will not equal {b: 2};

  • 考虑了 undefined 个项目,例如 [2] 不会等于 [2, undefined]

    ¥undefined items are taken into account, e.g. [2] will not equal [2, undefined];

  • 检查数组稀疏性,例如 [, 1] 不会等于 [undefined, 1]

    ¥array sparseness is checked, e.g. [, 1] will not equal [undefined, 1];

  • 检查对象类型,例如 具有字段 ab 的类实例不等于具有字段 ab 的字面量对象。

    ¥object types are checked, e.g. a class instance with fields a and b will not equal a literal object with fields a and 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?)

¥Also under the alias: .toThrowError(error?)

使用 .toThrow 来测试函数在调用时是否抛出异常。例如,如果我们想测试 drinkFlavor('octopus') 抛出异常,因为章鱼味太恶心了,不能喝,我们可以这样写:

¥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();
});
提示

你必须将代码封装在函数中,否则错误将不会被捕获并且断言将失败。

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

你可以提供一个可选参数来测试是否引发特定错误:

¥You can provide an optional argument to test that a specific error is thrown:

  • 正则表达式:错误消息与模式匹配

    ¥regular expression: error message matches the pattern

  • 字符串:错误消息包含子字符串

    ¥string: error message includes the substring

  • 错误对象:错误消息等于对象的 message 属性

    ¥error object: error message is equal to the message property of the object

  • 错误类:错误对象是类的实例

    ¥error class: error object is instance of class

例如,假设 drinkFlavor 的编码如下:

¥For example, let's say that drinkFlavor is coded like this:

function drinkFlavor(flavor) {
if (flavor == 'octopus') {
throw new DisgustingFlavorError('yuck, octopus flavor');
}
// Do some other stuff
}

我们可以通过多种方式测试此错误的抛出情况:

¥We could test this error gets thrown in several ways:

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

// Test that the error message says "yuck" somewhere: these are equivalent
expect(drinkOctopus).toThrow(/yuck/);
expect(drinkOctopus).toThrow('yuck');

// Test the exact error message
expect(drinkOctopus).toThrow(/^yuck, octopus flavor$/);
expect(drinkOctopus).toThrow(new Error('yuck, octopus flavor'));

// Test that we get a DisgustingFlavorError
expect(drinkOctopus).toThrow(DisgustingFlavorError);
});

.toThrowErrorMatchingSnapshot(hint?)

使用 .toThrowErrorMatchingSnapshot 测试函数在调用时是否抛出与最新快照匹配的错误。

¥Use .toThrowErrorMatchingSnapshot to test that a function throws an error matching the most recent snapshot when it is called.

你可以提供附加到测试名称的可选 hint 字符串参数。尽管 Jest 总是在快照名称末尾附加一个数字,但简短的描述性提示可能比数字更有用,可以区分单个 ittest 块中的多个快照。Jest 按相应 .snap 文件中的名称对快照进行排序。

¥You can provide an optional hint string argument that is appended to the test name. Although Jest always appends a number at the end of a snapshot name, short descriptive hints might be more useful than numbers to differentiate multiple snapshots in a single it or test block. Jest sorts snapshots by name in the corresponding .snap file.

例如,假设你有一个 drinkFlavor 函数,每当风味为 'octopus' 时就会抛出异常,代码如下:

¥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');
}
// Do some other stuff
}

该函数的测试将如下所示:

¥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"`;

查看 React 树快照测试 了解有关快照测试的更多信息。

¥Check out React Tree Snapshot Testing for more information on snapshot testing.

.toThrowErrorMatchingInlineSnapshot(inlineSnapshot)

使用 .toThrowErrorMatchingInlineSnapshot 测试函数在调用时是否抛出与最新快照匹配的错误。

¥Use .toThrowErrorMatchingInlineSnapshot to test that a function throws an error matching the most recent snapshot when it is called.

第一次运行测试时,Jest 将 inlineSnapshot 字符串参数添加到测试文件中的匹配器(而不是外部 .snap 文件)。

¥Jest adds the inlineSnapshot string argument to the matcher in the test file (instead of an external .snap file) the first time that the test runs.

查看 内联快照 部分以获取更多信息。

¥Check out the section on Inline Snapshots for more info.

不对称匹配器

¥Asymmetric Matchers

expect.anything()

expect.anything() 匹配除 nullundefined 之外的任何内容。你可以在 toEqualtoHaveBeenCalledWith 中使用它而不是字面量值。例如,如果你想检查是否使用非空参数调用模拟函数:

¥expect.anything() matches anything but null or undefined. You can use it inside toEqual or toHaveBeenCalledWith 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(x => mock(x));
expect(mock).toHaveBeenCalledWith(expect.anything());
});

expect.any(constructor)

expect.any(constructor) 匹配使用给定构造函数创建的任何内容,或者它是传递类型的基础类型。你可以在 toEqualtoHaveBeenCalledWith 中使用它而不是字面量值。例如,如果你想检查是否使用数字调用模拟函数:

¥expect.any(constructor) matches anything that was created with the given constructor or if it's a primitive that is of the passed type. You can use it inside toEqual or toHaveBeenCalledWith instead of a literal value. For example, if you want to check that a mock function is called with a number:

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).toHaveBeenCalledWith(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).toHaveBeenCalledWith(expect.any(Number));
});

expect.arrayContaining(array)

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:

  • toEqualtoHaveBeenCalledWith

    ¥in toEqual or toHaveBeenCalledWith

  • 匹配 objectContainingtoMatchObject 中的属性

    ¥to match a property in objectContaining or 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.not.arrayContaining(array)

expect.not.arrayContaining(array) 匹配接收到的数组,该数组不包含预期数组中的所有元素。也就是说,预期数组不是接收数组的子集。

¥expect.not.arrayContaining(array) matches a received array which does not contain all of the elements in the expected array. That is, the expected array is not a subset of the received array.

它是 expect.arrayContaining 的倒数。

¥It is the inverse of 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.closeTo(number, numDigits?)

expect.closeTo(number, numDigits?) 在比较对象属性或数组项中的浮点数时很有用。如果需要比较数字,请使用 .toBeCloseTo

¥expect.closeTo(number, numDigits?) is useful when comparing floating point numbers in object properties or array item. If you need to compare a number, please use .toBeCloseTo instead.

可选的 numDigits 参数限制小数点后要检查的位数。对于默认值 2,测试标准为 Math.abs(expected - received) < 0.005 (that is, 10 ** -2 / 2)

¥The optional numDigits argument limits the number of digits to check after the decimal point. For the default value 2, the test criterion is Math.abs(expected - received) < 0.005 (that is, 10 ** -2 / 2).

例如,此测试以 5 位精度通过:

¥For example, this test passes with a precision of 5 digits:

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.objectContaining(object)

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 present in the expected object.

你可以使用匹配器、expect.anything() 等,而不是预期对象中的字面量属性值。

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

例如,假设我们希望使用 Event 对象调用 onPress 函数,而我们需要验证的是该事件具有 event.xevent.y 属性。我们可以通过以下方式做到这一点:

¥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).toHaveBeenCalledWith(
expect.objectContaining({
x: expect.any(Number),
y: expect.any(Number),
}),
);
});

expect.not.objectContaining(object)

expect.not.objectContaining(object) 匹配任何未递归匹配预期属性的接收对象。也就是说,预期对象不是接收到的对象的子集。因此,它匹配接收到的对象,该对象包含预期对象中不存在的属性。

¥expect.not.objectContaining(object) matches any received object that does not recursively match the expected properties. That is, the expected object is not a subset of the received object. Therefore, it matches a received object which contains properties that are not in the expected object.

它是 expect.objectContaining 的倒数。

¥It is the inverse of 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.stringContaining(string)

如果 expect.stringContaining(string) 是包含确切预期字符串的字符串,则与接收到的值匹配。

¥expect.stringContaining(string) matches the received value if it is a string that contains the exact expected string.

expect.not.stringContaining(string)

如果 expect.not.stringContaining(string) 不是字符串或者不包含确切的预期字符串,则 expect.not.stringContaining(string) 与接收到的值匹配。

¥expect.not.stringContaining(string) matches the received value if it is not a string or if it is a string that does not contain the exact expected string.

它是 expect.stringContaining 的倒数。

¥It is the inverse of 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.stringMatching(string | regexp)

如果 expect.stringMatching(string | regexp) 是与预期字符串或正则表达式匹配的字符串,则与接收到的值匹配。

¥expect.stringMatching(string | regexp) matches the received value if it is a string that matches the expected string or regular expression.

你可以使用它来代替字面量值:

¥You can use it instead of a literal value:

  • toEqualtoHaveBeenCalledWith

    ¥in toEqual or toHaveBeenCalledWith

  • 匹配 arrayContaining 中的元素

    ¥to match an element in arrayContaining

  • 匹配 objectContainingtoMatchObject 中的属性

    ¥to match a property in objectContaining or toMatchObject

此示例还展示了如何嵌套多个不对称匹配器,其中 expect.stringMatching 位于 expect.arrayContaining 内。

¥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.not.stringMatching(string | regexp)

如果 expect.not.stringMatching(string | regexp) 不是字符串或者是与预期字符串或正则表达式不匹配的字符串,则 expect.not.stringMatching(string | regexp) 与接收到的值匹配。

¥expect.not.stringMatching(string | regexp) matches the received value if it is not a string or if it is a string that does not match the expected string or regular expression.

它是 expect.stringMatching 的倒数。

¥It is the inverse of 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));
});
});

断言计数

¥Assertion Count

expect.assertions(number)

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.

例如,假设我们有一个函数 doAsync,它接收两个回调 callback1callback2,它将以未知的顺序异步调用这两个回调。我们可以用以下方法进行测试:

¥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);
});

expect.assertions(2) 调用确保两个回调实际上都被调用。

¥The expect.assertions(2) call ensures that both callbacks actually get called.

expect.hasAssertions()

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.

例如,假设我们有一些处理状态的函数。prepareState 使用状态对象调用回调,validateState 在该状态对象上运行,waitOnState 返回一个等待所有 prepareState 回调完成的 promise。我们可以用以下方法进行测试:

¥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();
});

expect.hasAssertions() 调用确保 prepareState 回调实际上被调用。

¥The expect.hasAssertions() call ensures that the prepareState callback actually gets called.

扩展实用程序

¥Extend Utilities

expect.addEqualityTesters(testers)

你可以使用 expect.addEqualityTesters 添加自己的方法来测试两个对象是否相等。例如,假设你的代码中有一个表示体积的类,并且可以确定使用不同单位的两个体积是否相等。你可能希望 toEqual(和其他相等匹配器)在与 Volume 类进行比较时使用此自定义相等方法。你可以添加自定义相等测试器,以便在比较 Volume 类时让 toEqual 检测并应用自定义逻辑:

¥You can use expect.addEqualityTesters to add your own methods to test if two objects are equal. For example, let's say you have a class in your code that represents volume and can determine if two volumes using different units are equal. You may want toEqual (and other equality matchers) to use this custom equality method when comparing to Volume classes. You can add a custom equality tester to have toEqual detect and apply custom logic when comparing Volume classes:

Volume.js
// For simplicity in this example, we'll just support the units 'L' and 'mL'
export class Volume {
constructor(amount, unit) {
this.amount = amount;
this.unit = unit;
}

toString() {
return `[Volume ${this.amount}${this.unit}]`;
}

equals(other) {
if (this.unit === other.unit) {
return this.amount === other.amount;
} else if (this.unit === 'L' && other.unit === 'mL') {
return this.amount * 1000 === other.unit;
} else {
return this.amount === other.unit * 1000;
}
}
}
areVolumesEqual.js
import {expect} from '@jest/globals';
import {Volume} from './Volume.js';

function areVolumesEqual(a, b) {
const isAVolume = a instanceof Volume;
const isBVolume = b instanceof Volume;

if (isAVolume && isBVolume) {
return a.equals(b);
} else if (isAVolume === isBVolume) {
return undefined;
} else {
return false;
}
}

expect.addEqualityTesters([areVolumesEqual]);
__tests__/Volume.test.js
import {expect, test} from '@jest/globals';
import {Volume} from '../Volume.js';
import '../areVolumesEqual.js';

test('are equal with different units', () => {
expect(new Volume(1, 'L')).toEqual(new Volume(1000, 'mL'));
});

自定义相等测试器 API

¥Custom equality testers API

自定义测试器是返回比较两个给定参数相等性的结果(truefalse)的函数,或者如果测试器不处理给定对象并希望将相等性委托给其他测试器(例如,内置相等性测试器),则返回 undefined )。

¥Custom testers are functions that return either the result (true or false) of comparing the equality of the two given arguments or undefined if the tester does not handle the given objects and wants to delegate equality to other testers (for example, the builtin equality testers).

使用 3 个参数调用自定义测试器:要比较的两个对象和自定义测试器数组(用于递归测试器,请参阅下面的部分)。

¥Custom testers are called with 3 arguments: the two objects to compare and the array of custom testers (used for recursive testers, see the section below).

这些辅助函数和属性可以在自定义测试器内的 this 上找到:

¥These helper functions and properties can be found on this inside a custom tester:

this.equals(a, b, customTesters?)

这是一个深度相等函数,如果两个对象具有相同的值(递归地),它将返回 true。它可以选择使用自定义相等性测试人员列表来应用深度相等性检查。如果你使用此功能,请传递给你的测试人员的自定义测试人员,以便进一步应用 equals 的相等性检查也可以使用测试作者可能已配置的自定义测试人员。有关更多详细信息,请参阅 递归自定义相等测试器 部分中的示例。

¥This is a deep-equality function that will return true if two objects have the same values (recursively). It optionally takes a list of custom equality testers to apply to the deep equality checks. If you use this function, pass through the custom testers your tester is given so further equality checks equals applies can also use custom testers the test author may have configured. See the example in the Recursive custom equality testers section for more details.

匹配者与测试者

¥Matchers vs Testers

匹配器是 expect 上可用的方法,例如 expect().toEqual()toEqual 是匹配器。测试器是匹配器使用的一种方法,用于进行相等性检查以确定对象是否相同。

¥Matchers are methods available on expect, for example expect().toEqual(). toEqual is a matcher. A tester is a method used by matchers that do equality checks to determine if objects are the same.

当你想要提供测试作者可以在其测试中使用的自定义断言时,可以很好地使用自定义匹配器。例如,expect.extend 部分中的 toBeWithinRange 示例就是自定义匹配器的一个很好的示例。有时,测试作者可能想要断言两个数字完全相等,并且应该使用 toBe。然而,其他时候,测试作者可能希望在测试中允许一定的灵活性,并且 toBeWithinRange 可能是更合适的断言。

¥Custom matchers are good to use when you want to provide a custom assertion that test authors can use in their tests. For example, the toBeWithinRange example in the expect.extend section is a good example of a custom matcher. Sometimes a test author may want to assert two numbers are exactly equal and should use toBe. Other times, however, a test author may want to allow for some flexibility in their test, and toBeWithinRange may be a more appropriate assertion.

自定义相等测试器非常适合全局扩展 Jest 匹配器,以将自定义相等逻辑应用于所有相等比较。测试作者无法为某些断言打开自定义测试器,并为其他断言关闭它们(如果需要这种行为,则应使用自定义匹配器)。例如,定义如何检查所有匹配器的两个 Volume 对象是否相等将是一个很好的自定义相等测试器。

¥Custom equality testers are good for globally extending Jest matchers to apply custom equality logic for all equality comparisons. Test authors can't turn on custom testers for certain assertions and turn them off for others (a custom matcher should be used instead if that behavior is desired). For example, defining how to check if two Volume objects are equal for all matchers would be a good custom equality tester.

递归自定义相等测试器

¥Recursive custom equality testers

如果你的自定义相等测试器正在测试具有你想要进行深度相等的属性的对象,则应使用可供相等测试器使用的 this.equals 辅助程序。此 equals 方法与 Jest 内部用于所有深度相等比较的深度等于方法相同。它是调用自定义相等测试器的方法。它接受一组自定义相等测试器作为第三个参数。还为自定义相等测试器提供了一组自定义测试器作为其第三个参数。将此参数传递到 equals 的第三个参数中,以便对对象进行更深入的任何进一步的相等性检查也可以利用自定义相等性测试器。

¥If your custom equality testers are testing objects with properties you'd like to do deep equality with, you should use the this.equals helper available to equality testers. This equals method is the same deep equals method Jest uses internally for all of its deep equality comparisons. It's the method that invokes your custom equality tester. It accepts an array of custom equality testers as a third argument. Custom equality testers are also given an array of custom testers as their third argument. Pass this argument into the third argument of equals so that any further equality checks deeper into your object can also take advantage of custom equality testers.

例如,假设你有一个 Book 类,其中包含 Author 类的数组,并且这两个类都有自定义测试器。Book 自定义测试器想要对 Author 的数组进行深度相等性检查,并传递给它的自定义测试器,因此应用 Author 自定义相等性测试器:

¥For example, let's say you have a Book class that contains an array of Author classes and both of these classes have custom testers. The Book custom tester would want to do a deep equality check on the array of Authors and pass in the custom testers given to it, so the Authors custom equality tester is applied:

customEqualityTesters.js
function areAuthorEqual(a, b) {
const isAAuthor = a instanceof Author;
const isBAuthor = b instanceof Author;

if (isAAuthor && isBAuthor) {
// Authors are equal if they have the same name
return a.name === b.name;
} else if (isAAuthor === isBAuthor) {
return undefined;
} else {
return false;
}
}

function areBooksEqual(a, b, customTesters) {
const isABook = a instanceof Book;
const isBBook = b instanceof Book;

if (isABook && isBBook) {
// Books are the same if they have the same name and author array. We need
// to pass customTesters to equals here so the Author custom tester will be
// used when comparing Authors
return (
a.name === b.name && this.equals(a.authors, b.authors, customTesters)
);
} else if (isABook === isBBook) {
return undefined;
} else {
return false;
}
}

expect.addEqualityTesters([areAuthorsEqual, areBooksEqual]);
注意

请记住将相等测试器定义为常规函数而不是箭头函数,以便访问测试器上下文辅助程序(例如 this.equals)。

¥Remember to define your equality testers as regular functions and not arrow functions in order to access the tester context helpers (e.g. this.equals).

expect.addSnapshotSerializer(serializer)

你可以调用 expect.addSnapshotSerializer 添加格式化特定于应用的数据结构的模块。

¥You can call expect.addSnapshotSerializer to add a module that formats application-specific data structures.

对于单个测试文件,添加的模块位于 snapshotSerializers 配置中的任何模块之前,这些模块位于内置 JavaScript 类型和 React 元素的默认快照序列化器之前。最后添加的模块是第一个测试的模块。

¥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);

// affects expect(value).toMatchSnapshot() assertions in the test file

如果你在各个测试文件中添加快照序列化器而不是将其添加到 snapshotSerializers 配置中:

¥If you add a snapshot serializer in individual test files instead of adding it to snapshotSerializers configuration:

  • 你使依赖显式而不是隐式。

    ¥You make the dependency explicit instead of implicit.

  • 你可以避免可能导致你从 create-react-app 弹出的配置限制。

    ¥You avoid limits to configuration that might cause you to eject from create-react-app.

请参阅 配置 Jest 了解更多信息。

¥See configuring Jest for more information.

expect.extend(matchers)

你可以使用 expect.extend 将你自己的匹配器添加到 Jest。例如,假设你正在测试一个数字实用程序库,并且经常断言数字出现在其他数字的特定范围内。你可以将其抽象为 toBeWithinRange 匹配器:

¥You can use expect.extend to add your own matchers to Jest. For example, let's say that you're testing a number utility library and you're frequently asserting that numbers appear within particular ranges of other numbers. You could abstract that into a toBeWithinRange matcher:

toBeWithinRange.js
import {expect} from '@jest/globals';

function toBeWithinRange(actual, floor, ceiling) {
if (
typeof actual !== 'number' ||
typeof floor !== 'number' ||
typeof ceiling !== 'number'
) {
throw new TypeError('These must be of type number!');
}

const pass = actual >= floor && actual <= ceiling;
if (pass) {
return {
message: () =>
`expected ${this.utils.printReceived(
actual,
)} not to be within range ${this.utils.printExpected(
`${floor} - ${ceiling}`,
)}`,
pass: true,
};
} else {
return {
message: () =>
`expected ${this.utils.printReceived(
actual,
)} to be within range ${this.utils.printExpected(
`${floor} - ${ceiling}`,
)}`,
pass: false,
};
}
}

expect.extend({
toBeWithinRange,
});
__tests__/ranges.test.js
import {expect, test} from '@jest/globals';
import '../toBeWithinRange';

test('is within range', () => expect(100).toBeWithinRange(90, 110));

test('is NOT within range', () => expect(101).not.toBeWithinRange(0, 100));

test('asymmetric ranges', () => {
expect({apples: 6, bananas: 3}).toEqual({
apples: expect.toBeWithinRange(1, 10),
bananas: expect.not.toBeWithinRange(11, 20),
});
});
toBeWithinRange.d.ts
// optionally add a type declaration, e.g. it enables autocompletion in IDEs
declare module 'expect' {
interface AsymmetricMatchers {
toBeWithinRange(floor: number, ceiling: number): void;
}
interface Matchers<R> {
toBeWithinRange(floor: number, ceiling: number): R;
}
}

export {};
提示

匹配器的类型声明可以存在于 .d.ts 文件中或导入的 .ts 模块中(分别参见上面的 JS 和 TS 示例)。如果将声明保留在 .d.ts 文件中,请确保它包含在程序中并且是有效的模块,即它至少有一个空的 export {}

¥The type declaration of the matcher can live in a .d.ts file or in an imported .ts module (see JS and TS examples above respectively). If you keep the declaration in a .d.ts file, make sure that it is included in the program and that it is a valid module, i.e. it has at least an empty export {}.

提示

你可以通过将 expect.extend 调用移至 setupFilesAfterEnv 脚本来为所有测试启用匹配器,而不是将 toBeWithinRange 模块导入到测试文件中:

¥Instead of importing toBeWithinRange module to the test file, you can enable the matcher for all tests by moving the expect.extend call to a setupFilesAfterEnv script:

import {expect} from '@jest/globals';
// remember to export `toBeWithinRange` as well
import {toBeWithinRange} from './toBeWithinRange';

expect.extend({
toBeWithinRange,
});

异步匹配器

¥Async Matchers

expect.extend 还支持异步匹配器。异步匹配器返回 Promise,因此你需要等待返回值。让我们使用一个示例匹配器来说明它们的用法。我们将实现一个名为 toBeDivisibleByExternalValue 的匹配器,其中可整除的数字将从外部源中提取。

¥expect.extend also supports async matchers. Async matchers return a Promise so you will need to await the returned value. Let's use an example matcher to illustrate the usage of them. We are going to implement a matcher called toBeDivisibleByExternalValue, where the divisible number is going to be pulled from an external source.

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

¥Custom Matchers API

匹配器应该返回一个带有两个键的对象(或对象的 Promise)。pass 表示是否匹配,message 提供一个不带参数的函数,在失败时返回错误消息。因此,当 pass 为 false 时,message 应该返回 expect(x).yourMatcher() 失败时的错误消息。当 pass 为 true 时,message 应该返回 expect(x).not.yourMatcher() 失败时的错误消息。

¥Matchers should return an object (or a Promise of 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.

调用匹配器时,将参数传递给 expect(x),然后将参数传递给 .yourMatcher(y, z)

¥Matchers are called with the argument passed to expect(x) followed by the arguments passed to .yourMatcher(y, z):

expect.extend({
yourMatcher(x, y, z) {
return {
pass: true,
message: () => '',
};
},
});

这些辅助函数和属性可以在 this 上的自定义匹配器中找到:

¥These helper functions and properties can be found on this inside a custom matcher:

this.isNot

一个布尔值,让你知道此匹配器是使用否定的 .not 修饰符调用的,允许你显示清晰且正确的匹配器提示(请参阅示例代码)。

¥A boolean to let you know this matcher was called with the negated .not modifier allowing you to display a clear and correct matcher hint (see example code).

this.promise

一个字符串,允许你显示清晰且正确的匹配器提示:

¥A string allowing you to display a clear and correct matcher hint:

  • 'rejects' 如果使用 Promise .rejects 修饰符调用匹配器

    ¥'rejects' if matcher was called with the promise .rejects modifier

  • 'resolves' 如果使用 Promise .resolves 修饰符调用匹配器

    ¥'resolves' if matcher was called with the promise .resolves modifier

  • '' 如果没有使用 Promise 修饰符调用匹配器

    ¥'' if matcher was not called with a promise modifier

this.equals(a, b, customTesters?)

这是一个深度相等函数,如果两个对象具有相同的值(递归地),它将返回 true。它可以选择使用自定义相等性测试程序列表来应用深度相等性检查(请参阅下面的 this.customTesters)。

¥This is a deep-equality function that will return true if two objects have the same values (recursively). It optionally takes a list of custom equality testers to apply to the deep equality checks (see this.customTesters below).

this.expand

一个布尔值,让你知道这个匹配器是使用 expand 选项调用的。当使用 --expand 标志调用 Jest 时,this.expand 可用于确定 Jest 是否应显示完整的差异和错误。

¥A boolean to let you know this matcher was called with an expand option. When Jest is called with the --expand flag, this.expand can be used to determine if Jest is expected to show full diffs and errors.

this.utils

this.utils 上公开了许多有用的工具,主要包括 jest-matcher-utils 的导出。

¥There are a number of helpful tools exposed on this.utils primarily consisting of the exports from jest-matcher-utils.

最有用的是 matcherHintprintExpectedprintReceived,可以很好地格式化错误消息。例如,看一下 toBe 匹配器的实现:

¥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 options = {
comment: 'Object.is equality',
isNot: this.isNot,
promise: this.promise,
};

const pass = Object.is(received, expected);

const message = pass
? () =>
// eslint-disable-next-line prefer-template
this.utils.matcherHint('toBe', undefined, undefined, options) +
'\n\n' +
`Expected: not ${this.utils.printExpected(expected)}\n` +
`Received: ${this.utils.printReceived(received)}`
: () => {
const diffString = diff(expected, received, {
expand: this.expand,
});
return (
// eslint-disable-next-line prefer-template
this.utils.matcherHint('toBe', undefined, undefined, options) +
'\n\n' +
(diffString && diffString.includes('- Expect')
? `Difference:\n\n${diffString}`
: `Expected: ${this.utils.printExpected(expected)}\n` +
`Received: ${this.utils.printReceived(received)}`)
);
};

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

这将打印如下内容:

¥This will print something like this:

  expect(received).toBe(expected)

Expected value to be (using Object.is):
"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.

this.customTesters

如果你的匹配器使用 this.equals 进行深度相等检查,你可能希望将用户提供的自定义测试器传递给 this.equals。用户使用 addEqualityTesters API 提供的自定义相等测试器可在此属性上使用。内置的 Jest 匹配器将 this.customTesters(以及其他内置测试器)传递给 this.equals 以进行深度相等,并且你的自定义匹配器可能想要执行相同的操作。

¥If your matcher does a deep equality check using this.equals, you may want to pass user-provided custom testers to this.equals. The custom equality testers the user has provided using the addEqualityTesters API are available on this property. The built-in Jest matchers pass this.customTesters (along with other built-in testers) to this.equals to do deep equality, and your custom matchers may want to do the same.

自定义快照匹配器

¥Custom snapshot matchers

要在自定义匹配器中使用快照测试,你可以导入 jest-snapshot 并在匹配器中使用它。

¥To use snapshot testing inside of your custom matcher you can import jest-snapshot and use it from within your matcher.

这是一个快照匹配器,它修剪要存储的给定长度 .toMatchTrimmedSnapshot(length) 的字符串:

¥Here's a snapshot matcher that trims a string to store for a given length, .toMatchTrimmedSnapshot(length):

const {toMatchSnapshot} = require('jest-snapshot');

expect.extend({
toMatchTrimmedSnapshot(received, length) {
return toMatchSnapshot.call(
this,
received.slice(0, length),
'toMatchTrimmedSnapshot',
);
},
});

it('stores only 10 characters', () => {
expect('extra long string oh my gerd').toMatchTrimmedSnapshot(10);
});

/*
Stored snapshot will look like:

exports[`stores only 10 characters: toMatchTrimmedSnapshot 1`] = `"extra long"`;
*/

还可以为内联快照创建自定义匹配器,快照将正确添加到自定义匹配器中。但是,当第一个参数是属性匹配器时,内联快照将始终尝试附加到第一个参数或第二个参数,因此不可能在自定义匹配器中接受自定义参数。

¥It's also possible to create custom matchers for inline snapshots, the snapshots will be correctly added to the custom matchers. However, inline snapshot will always try to append to the first argument or the second when the first argument is the property matcher, so it's not possible to accept custom arguments in the custom matchers.

const {toMatchInlineSnapshot} = require('jest-snapshot');

expect.extend({
toMatchTrimmedInlineSnapshot(received, ...rest) {
return toMatchInlineSnapshot.call(this, received.slice(0, 10), ...rest);
},
});

it('stores only 10 characters', () => {
expect('extra long string oh my gerd').toMatchTrimmedInlineSnapshot();
/*
The snapshot will be added inline like
expect('extra long string oh my gerd').toMatchTrimmedInlineSnapshot(
`"extra long"`
);
*/
});

async

如果你的自定义内联快照匹配器是异步的,即使用 async-await,你可能会遇到类似 "不支持同一调用的多个内联快照" 的错误。Jest 需要额外的上下文信息来查找自定义内联快照匹配器用于正确更新快照的位置。

¥If your custom inline snapshot matcher is async i.e. uses async-await you might encounter an error like "Multiple inline snapshots for the same call are not supported". Jest needs additional context information to find where the custom inline snapshot matcher was used to update the snapshots properly.

const {toMatchInlineSnapshot} = require('jest-snapshot');

expect.extend({
async toMatchObservationInlineSnapshot(fn, ...rest) {
// The error (and its stacktrace) must be created before any `await`
this.error = new Error();

// The implementation of `observe` doesn't matter.
// It only matters that the custom snapshot matcher is async.
const observation = await observe(async () => {
await fn();
});

return toMatchInlineSnapshot.call(this, recording, ...rest);
},
});

it('observes something', async () => {
await expect(async () => {
return 'async action';
}).toMatchTrimmedInlineSnapshot();
/*
The snapshot will be added inline like
await expect(async () => {
return 'async action';
}).toMatchTrimmedInlineSnapshot(`"async action"`);
*/
});

帮助

¥Bail out

通常,jest 会尝试匹配测试中预期的每个快照。

¥Usually jest tries to match every snapshot that is expected in a test.

有时,如果先前的快照失败,则继续测试可能没有意义。例如,当你在各种转换后制作状态机的快照时,一旦一个转换产生错误的状态,你就可以中止测试。

¥Sometimes it might not make sense to continue the test if a prior snapshot failed. For example, when you make snapshots of a state-machine after various transitions you can abort the test once one transition produced the wrong state.

在这种情况下,你可以实现一个自定义快照匹配器,该快照匹配器会抛出第一个不匹配的情况,而不是收集每个不匹配的情况。

¥In that case you can implement a custom snapshot matcher that throws on the first mismatch instead of collecting every mismatch.

const {toMatchInlineSnapshot} = require('jest-snapshot');

expect.extend({
toMatchStateInlineSnapshot(...args) {
this.dontThrow = () => {};

return toMatchInlineSnapshot.call(this, ...args);
},
});

let state = 'initial';

function transition() {
// Typo in the implementation should cause the test to fail
if (state === 'INITIAL') {
state = 'pending';
} else if (state === 'pending') {
state = 'done';
}
}

it('transitions as expected', () => {
expect(state).toMatchStateInlineSnapshot(`"initial"`);

transition();
// Already produces a mismatch. No point in continuing the test.
expect(state).toMatchStateInlineSnapshot(`"loading"`);

transition();
expect(state).toMatchStateInlineSnapshot(`"done"`);
});