Jest expect API
在编写测试时,经常需要检查值是否满足特定条件。expect可以访问许多匹配器(Matchers),这些匹配器让你验证不同的事物。
有关 Jest 社区维护的其他 Jest 匹配器,请查看jest-extended。
方法
- expect(value)
- expect.extend(matchers)
- expect.anything()
- expect.any(constructor)
- expect.arrayContaining(array)
- expect.assertions(number)
- 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(regexpOrString)
- .toMatchObject(object)
- .toMatchSnapshot(propertyMatchers?, hint?)
- .toMatchInlineSnapshot(propertyMatchers?, inlineSnapshot)
- .toStrictEqual(value)
- .toThrow(error?)
- .toThrowErrorMatchingSnapshot(hint?)
- .toThrowErrorMatchingInlineSnapshot(inlineSnapshot)
参考
expect(value)
每次要测试一个值时都会使用expect函数。 你很少会自己调用expect。 相反,你会使用expect和“matcher”函数来断言有关值的内容。
很容易理解这一点的一个例子。 假设你有一个方法bestLaCroixFlavor(),它应该返回字符串'grapefruit'。 以下是如何测试:
test('the best flavor is grapefruit', () => {expect(bestLaCroixFlavor()).toBe('grapefruit');});
在这种情况下,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),});});
注意:在 TypeScript 中,@types/jest例如使用时,可以toBeWithinRange像这样声明新的匹配器:
declare global {namespace jest {interface Matchers<R> {toBeWithinRange(a: number, b: number): R;}}}
异步匹配器
expect.extend还支持异步匹配器。异步匹配器返回一个 Promise,因此你需要等待返回的值。让我们使用一个示例匹配器来说明它们的用法。我们将实现一个名为 的匹配器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修饰符调用的,允许显示清晰正确的匹配器提示(请参阅示例代码)。
this.promise
一个字符串,允许显示清晰正确的匹配器提示:
-
'rejects'如果使用 promise.rejects修饰符调用 matcher -
'resolves'如果使用 promise.resolves修饰符调用 matcher -
'' 如果没有使用承诺修饰符调用匹配器
this.equals(a, b)
这是一个深度相等的函数,如果两个对象具有相同的值(递归),则返回true。
this.expand
一个布尔值,让你知道这个匹配器是用一个expand选项调用的。当使用--expand标志调用 Jest 时,this.expand可用于确定 Jest 是否应显示完整的差异和错误。
this.utils
在this.utils上有一些有用的工具,主要由jest-matcher-utils导出。
最有用的是matcherHint,printExpected和printReceived很好地格式化错误消息。例如,看一下toBe匹配器的实现:
const diff = require('jest-diff');expect.extend({toBe(received, expected) {const options = {comment: 'Object.is equality',isNot: this.isNot,promise: this.promise,};const pass = Object.is(received, expected);const message = pass? () =>this.utils.matcherHint('toBe', undefined, undefined, options) +'\n\n' +`Expected: not ${this.utils.printExpected(expected)}\n` +`Received: ${this.utils.printReceived(received)}`: () => {const diffString = diff(expected, received, {expand: this.expand,});return (this.utils.matcherHint('toBe', undefined, undefined, options) +'\n\n' +(diffString && diffString.includes('- Expect')? `Difference:\n\n${diffString}`: `Expected: ${this.utils.printExpected(expected)}\n` +`Received: ${this.utils.printReceived(received)}`));};return {actual: received, message, pass};},});
这将打印如下内容:
expect(received).toBe(expected)Expected value to be (using Object.is):"banana"Received:"apple"
当断言失败时,错误消息应向用户提供尽可能多的信号,以便他们能够快速解决问题。应该制作精确的失败消息,以确保你的自定义断言的用户拥有良好的开发人员体验。
自定义快照匹配器
要在自定义匹配器中使用快照测试,可以jest-snapshot从匹配器中导入和使用它。
这是一个快照匹配器,它修剪字符串以存储给定长度,.toMatchTrimmedSnapshot(length):
const {toMatchSnapshot} = require('jest-snapshot');expect.extend({toMatchTrimmedSnapshot(received, length) {return toMatchSnapshot.call(this,received.substring(0, length),'toMatchTrimmedSnapshot',);},});it('stores only 10 characters', () => {expect('extra long string oh my gerd').toMatchTrimmedSnapshot(10);});/*Stored snapshot will look like:exports[`stores only 10 characters: toMatchTrimmedSnapshot 1`] = `"extra long"`;*/
也可以为内联快照创建自定义匹配器,快照将正确添加到自定义匹配器中。但是,当第一个参数是属性匹配器时,内联快照将始终尝试附加到第一个参数或第二个参数,因此无法在自定义匹配器中接受自定义参数。
const {toMatchInlineSnapshot} = require('jest-snapshot');expect.extend({toMatchTrimmedInlineSnapshot(received) {return toMatchInlineSnapshot.call(this, received.substring(0, 10));},});it('stores only 10 characters', () => {expect('extra long string oh my gerd').toMatchTrimmedInlineSnapshot();/*The snapshot will be added inline likeexpect('extra long string oh my gerd').toMatchTrimmedInlineSnapshot(`"extra long"`);*/});
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代替文字值使用它。例如,如果要检查是否使用数字调用了模拟函数:
function randocall(fn) {return fn(Math.floor(Math.random() * 6 + 1));}test('randocall calls its callback with a number', () => {const mock = jest.fn();randocall(mock);expect(mock).toBeCalledWith(expect.any(Number));});
expect.arrayContaining(array)
expect.arrayContaining(array)匹配接收到的数组,该数组包含预期数组中的所有元素。也就是说,预期数组是接收数组的子集。因此,它匹配包含不在预期数组中的元素的接收数组。
可以使用它代替文字值:
- 在
toEqual或toBeCalledWith - 匹配
objectContaining或toMatchObject
describe('arrayContaining', () => {const expected = ['Alice', 'Bob'];it('matches even if received contains additional elements', () => {expect(['Alice', 'Bob', 'Eve']).toEqual(expect.arrayContaining(expected));});it('does not match if received does not contain expected elements', () => {expect(['Bob', 'Eve']).not.toEqual(expect.arrayContaining(expected));});});
describe('Beware of a misunderstanding! A sequence of dice rolls', () => {const expected = [1, 2, 3, 4, 5, 6];it('matches even with an unexpected number 7', () => {expect([4, 1, 6, 7, 3, 5, 2, 5, 4, 6]).toEqual(expect.arrayContaining(expected),);});it('does not match without an expected number 2', () => {expect([4, 1, 6, 7, 3, 5, 7, 5, 4, 6]).not.toEqual(expect.arrayContaining(expected),);});});
expect.assertions(number)
expect.assertions(number)验证在测试期间调用了一定数量的断言。这在测试异步代码时通常很有用,以确保回调中的断言确实被调用。
例如,假设我们有一个函数doAsync接收两个回调callback1和callback2,它将以未知顺序异步调用它们。我们可以用以下方法测试:
test('doAsync calls both callbacks', () => {expect.assertions(2);function callback1(data) {expect(data).toBeTruthy();}function callback2(data) {expect(data).toBeTruthy();}doAsync(callback1, callback2);});
该expect.assertions(2)调用确保两个回调都被实际调用。
expect.hasAssertions()
expect.hasAssertions()验证在测试期间至少调用了一个断言。这在测试异步代码时通常很有用,以确保回调中的断言确实被调用。
例如,假设我们有一些处理状态的函数。prepareState使用状态对象调用回调,validateState在该状态对象上运行,并waitOnState返回一个等待所有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);// affects expect(value).toMatchSnapshot() assertions in the test file
如果在单个测试文件中添加快照序列化程序而不是将其添加到snapshotSerializers配置中:
- 使依赖显式而不是隐式。
- 避免了可能导致从create-react-app 中弹出的配置限制。
有关更多信息,请参阅配置 Jest。
.not
如果你知道如何测试某样东西,.not让你测试它的反面。例如,此代码测试最好的 La Croix 风味不是椰子:
test('the best flavor is not coconut', () => {expect(bestLaCroixFlavor()).not.toBe('coconut');});
.resolves
使用.resolves解开一个兑现承诺的价值,所以任何其他匹配可以链接。如果承诺被拒绝,则断言失败。
例如,此代码测试 promise 是否已解析并且结果值为'lemon':
test('resolves to lemon', () => {// make sure to add a return statementreturn expect(Promise.resolve('lemon')).resolves.toBe('lemon');});
请注意,由于仍在测试 promise,因此测试仍然是异步的。因此,需要通过返回未包装的断言来告诉 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拆开包装,因此任何其他匹配可链接被拒绝承诺的理由。如果承诺被实现,则断言失败。
例如,此代码测试 Promise 是否以 reason 拒绝'octopus':
test('rejects to octopus', () => {// make sure to add a return statementreturn expect(Promise.reject(new Error('octopus'))).rejects.toThrow('octopus',);});
请注意,由于仍在测试 promise,因此测试仍然是异步的。因此,需要通过返回未包装的断言来告诉 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与浮点数一起使用。例如,由于四舍五入,在 JavaScript0.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()
使用.toHaveBeenCalled以确保模拟功能得到调用。
例如,假设你有一个drinkAll(drink, flavour)函数,它接受一个drink函数并将其应用于所有可用的饮料。你可能想检查是否调用了 drinkfor 'lemon',而不是 for '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以确保模拟函数被调用的具体参数。
例如,假设你可以使用register函数注册饮料,并且applyToAll(f)应该将该函数f应用于所有已注册的饮料。为了确保这有效,你可以写:
test('registration applies correctly to orange La Croix', () => {const beverage = new LaCroix('orange');register(beverage);const f = jest.fn();applyToAll(f);expect(f).toHaveBeenCalledWith(beverage);});
.toHaveBeenLastCalledWith(arg1, arg2, ...)
同样在别名下: .lastCalledWith(arg1, arg2, ...)
如果你有一个模拟函数,你可以.toHaveBeenLastCalledWith用来测试它最后被调用的参数。例如,假设你有一个applyToAllFlavors(f)适用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用来测试它被调用的参数。例如,假设你有一个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');});
注意:第 n 个参数必须是从 1 开始的正整数。
.toHaveReturned()
同样在别名下: .toReturn()
如果你有一个模拟函数,你可以.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)');});
注意:第 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 的数组。
你可以提供一个可选value参数来比较接收到的属性值(递归地用于对象实例的所有属性,也称为深度相等,如toEqual匹配器)。
以下示例包含houseForSale具有嵌套属性的对象。我们toHaveProperty用来检查对象中各种属性的存在和值。
// Object containing house features to be testedconst houseForSale = {bath: true,bedrooms: 4,kitchen: {amenities: ['oven', 'stove', 'washer'],area: 20,wallColor: 'white','nice.oven': true,},'ceiling.height': 2,};test('this house has my desired features', () => {// Example Referencingexpect(houseForSale).toHaveProperty('bath');expect(houseForSale).toHaveProperty('bedrooms', 4);expect(houseForSale).not.toHaveProperty('pool');// Deep referencing using dot notationexpect(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 keyPathexpect(houseForSale).toHaveProperty(['kitchen', 'area'], 20);expect(houseForSale).toHaveProperty(['kitchen', 'amenities'],['oven', 'stove', 'washer'],);expect(houseForSale).toHaveProperty(['kitchen', 'amenities', 0], 'oven');expect(houseForSale).toHaveProperty(['kitchen', 'nice.oven']);expect(houseForSale).not.toHaveProperty(['kitchen', 'open']);// Referencing keys with dot in the key itselfexpect(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); // Fails!});
它失败了,因为在 JavaScript 中,0.2 + 0.1实际上是0.30000000000000004.
例如,此测试以 5 位数的精度通过:
test('adding works sanely with decimals', () => {expect(0.2 + 0.1).toBeCloseTo(0.3, 5);});
因为浮点错误是要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中,有六个falsy值: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); // throws
.toBeNull()
.toBeNull()与相同.toBe(null)但错误消息更好一些。所以.toBeNull()当你想检查某些东西是否为空时使用。
function bloop() {return null;}test('bloop returns null', () => {expect(bloop()).toBeNull();});
.toBeTruthy()
使用.toBeTruthy时,你不关心的值是什么,你要确保一个值在布尔环境是真实的。例如,假设你有一些如下所示的应用程序代码:
drinkSomeLaCroix();if (thirstInfo()) {drinkMoreLaCroix();}
你可能不在乎thirstInfo返回什么,特别是它可能返回true或者一个复杂的对象,并且你的代码仍然可以工作。所以如果你想测试在喝了一些 La Croix 后thirstInfo是否真实,你可以写:
test('drinking La Croix leads to having thirst info', () => {drinkSomeLaCroix();expect(thirstInfo()).toBeTruthy();});
在JavaScript中,有六个falsy值:false,0,'',null,undefined,和NaN。其他一切都是真实的。
.toBeUndefined()
使用.toBeUndefined检查变量不确定。例如,如果你想检查一个函数bestDrinkForFlavor(flavor)返回undefined的'octopus'味道,因为没有好的octopus-flavored饮料:
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');});
.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);});});
注意:.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(regexpOrString)
使用.toMatch检查字符串中的正则表达式匹配。
例如,你可能不知道究竟essayOnTheBestFlavor()返回什么,但你知道它是一个非常长的字符串,并且子字符串grapefruit应该在某个地方。可以使用以下方法进行测试:
describe('an essay on the best flavor', () => {test('mentions grapefruit', () => {expect(essayOnTheBestFlavor()).toMatch(/grapefruit/);expect(essayOnTheBestFlavor()).toMatch(new RegExp('grapefruit'));});});
这个匹配器还接受一个字符串,它将尝试匹配:
describe('grapefruits are healthy', () => {test('grapefruits are a fruit', () => {expect('grapefruits').toMatch('fruit');});});
.toMatchObject(object)
使用.toMatchObject检查JavaScript对象对象的属性的子集相匹配。它会将接收到的对象与不在预期对象中的属性进行匹配。
还可以传递一个对象数组,在这种情况下,只有当接收到的数组中的每个对象都匹配(在上述toMatchObject意义上)预期数组中的相应对象时,该方法才会返回 true 。如果你想检查两个数组的元素数量是否匹配,这很有用,而不是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 总是在快照名称的末尾附加一个数字,但在区分单个或块中的多个快照时,简短的描述性提示可能比数字更有用。Jest 在相应文件中按名称对快照进行排序。 ittest.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();});
注意:必须将代码包裹在一个函数中,否则无法捕获错误,断言失败。
可以提供一个可选参数来测试是否抛出了特定错误:
- 正则表达式:错误消息与模式匹配
- 字符串:错误消息包括子字符串
- 错误对象:错误消息等于对象的消息属性
- 错误类:错误对象是类的实例
例如,假设它drinkFlavor是这样编码的:
function drinkFlavor(flavor) {if (flavor == 'octopus') {throw new DisgustingFlavorError('yuck, octopus flavor');}// Do some other stuff}
我们可以通过几种方式测试这个错误是否被抛出:
test('throws on octopus', () => {function drinkOctopus() {drinkFlavor('octopus');}// Test that the error message says "yuck" somewhere: these are equivalentexpect(drinkOctopus).toThrowError(/yuck/);expect(drinkOctopus).toThrowError('yuck');// Test the exact error messageexpect(drinkOctopus).toThrowError(/^yuck, octopus flavor$/);expect(drinkOctopus).toThrowError(new Error('yuck, octopus flavor'));// Test that we get a DisgustingFlavorErrorexpect(drinkOctopus).toThrowError(DisgustingFlavorError);});
.toThrowErrorMatchingSnapshot(hint?)
使用.toThrowErrorMatchingSnapshot测试一个函数抛出匹配最新的快照时,它被称为一个错误。
可以提供hint附加到测试名称的可选字符串参数。尽管 Jest 总是在快照名称的末尾附加一个数字,但在区分单个或块中的多个快照时,简短的描述性提示可能比数字更有用。Jest 在相应文件中按名称对快照进行排序。 ittest.snap
例如,假设你有一个drinkFlavor函数,该函数在风味为 时抛出'octopus',其编码如下:
function drinkFlavor(flavor) {if (flavor == 'octopus') {throw new DisgustingFlavorError('yuck, octopus flavor');}// Do some other stuff}
此函数的测试将如下所示:
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文件)中的匹配器。
查看内联快照部分了解更多信息。