Jest expect API

2021-09-18 20:53 更新

在编写测试时,经常需要检查值是否满足特定条件。expect可以访问许多匹配器(Matchers),这些匹配器让你验证不同的事物。

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

方法

参考

​expect(value)​

每次要测试一个值时都会使用​expect​函数。 你很少会自己调用​expect​。 相反,你会使用​expect​和“matcher”函数来断言有关值的内容。

很容易理解这一点的一个例子。 假设你有一个方法​bestLaCroixFlavor()​,它应该返回字符串​'grapefruit'​。 以下是如何测试:

  1. test('the best flavor is grapefruit', () => {
  2. expect(bestLaCroixFlavor()).toBe('grapefruit');
  3. });

在这种情况下,​toBe​是匹配器功能。有许多不同的匹配器函数,记录如下,来帮助你测试不同的东西。

expect​的参数应该是代码产生的值,匹配器的任何参数应该是正确的值。 如果混合使用,测试仍然可以工作,但是失败测试的错误信息将会显得奇怪。

expect.extend(matchers)

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

  1. expect.extend({
  2. toBeWithinRange(received, floor, ceiling) {
  3. const pass = received >= floor && received <= ceiling;
  4. if (pass) {
  5. return {
  6. message: () =>
  7. `expected ${received} not to be within range ${floor} - ${ceiling}`,
  8. pass: true,
  9. };
  10. } else {
  11. return {
  12. message: () =>
  13. `expected ${received} to be within range ${floor} - ${ceiling}`,
  14. pass: false,
  15. };
  16. }
  17. },
  18. });
  19. test('numeric ranges', () => {
  20. expect(100).toBeWithinRange(90, 110);
  21. expect(101).not.toBeWithinRange(0, 100);
  22. expect({apples: 6, bananas: 3}).toEqual({
  23. apples: expect.toBeWithinRange(1, 10),
  24. bananas: expect.not.toBeWithinRange(11, 20),
  25. });
  26. });

注意:在 TypeScript 中,​@types/jest​例如使用时,可以​toBeWithinRange​像这样声明新的匹配器:

  1. declare global {
  2. namespace jest {
  3. interface Matchers<R> {
  4. toBeWithinRange(a: number, b: number): R;
  5. }
  6. }
  7. }

异步匹配器

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

  1. expect.extend({
  2. async toBeDivisibleByExternalValue(received) {
  3. const externalValue = await getExternalValueFromRemoteSource();
  4. const pass = received % externalValue == 0;
  5. if (pass) {
  6. return {
  7. message: () =>
  8. `expected ${received} not to be divisible by ${externalValue}`,
  9. pass: true,
  10. };
  11. } else {
  12. return {
  13. message: () =>
  14. `expected ${received} to be divisible by ${externalValue}`,
  15. pass: false,
  16. };
  17. }
  18. },
  19. });
  20. test('is divisible by external value', async () => {
  21. await expect(100).toBeDivisibleByExternalValue();
  22. await expect(101).not.toBeDivisibleByExternalValue();
  23. });

自定义匹配器 API

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

匹配器使用传递给​expect(x)​的参数和传递给的参数调用​.yourMatcher(y, z)​:

  1. expect.extend({
  2. yourMatcher(x, y, z) {
  3. return {
  4. pass: true,
  5. message: () => '',
  6. };
  7. },
  8. });

这些辅助函数和属性可以​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​匹配器的实现:

  1. const diff = require('jest-diff');
  2. expect.extend({
  3. toBe(received, expected) {
  4. const options = {
  5. comment: 'Object.is equality',
  6. isNot: this.isNot,
  7. promise: this.promise,
  8. };
  9. const pass = Object.is(received, expected);
  10. const message = pass
  11. ? () =>
  12. this.utils.matcherHint('toBe', undefined, undefined, options) +
  13. '\n\n' +
  14. `Expected: not ${this.utils.printExpected(expected)}\n` +
  15. `Received: ${this.utils.printReceived(received)}`
  16. : () => {
  17. const diffString = diff(expected, received, {
  18. expand: this.expand,
  19. });
  20. return (
  21. this.utils.matcherHint('toBe', undefined, undefined, options) +
  22. '\n\n' +
  23. (diffString && diffString.includes('- Expect')
  24. ? `Difference:\n\n${diffString}`
  25. : `Expected: ${this.utils.printExpected(expected)}\n` +
  26. `Received: ${this.utils.printReceived(received)}`)
  27. );
  28. };
  29. return {actual: received, message, pass};
  30. },
  31. });

这将打印如下内容:

  1. expect(received).toBe(expected)
  2. Expected value to be (using Object.is):
  3. "banana"
  4. Received:
  5. "apple"

当断言失败时,错误消息应向用户提供尽可能多的信号,以便他们能够快速解决问题。应该制作精确的失败消息,以确保你的自定义断言的用户拥有良好的开发人员体验。

自定义快照匹配器

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

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

  1. const {toMatchSnapshot} = require('jest-snapshot');
  2. expect.extend({
  3. toMatchTrimmedSnapshot(received, length) {
  4. return toMatchSnapshot.call(
  5. this,
  6. received.substring(0, length),
  7. 'toMatchTrimmedSnapshot',
  8. );
  9. },
  10. });
  11. it('stores only 10 characters', () => {
  12. expect('extra long string oh my gerd').toMatchTrimmedSnapshot(10);
  13. });
  14. /*
  15. Stored snapshot will look like:
  16. exports[`stores only 10 characters: toMatchTrimmedSnapshot 1`] = `"extra long"`;
  17. */

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

  1. const {toMatchInlineSnapshot} = require('jest-snapshot');
  2. expect.extend({
  3. toMatchTrimmedInlineSnapshot(received) {
  4. return toMatchInlineSnapshot.call(this, received.substring(0, 10));
  5. },
  6. });
  7. it('stores only 10 characters', () => {
  8. expect('extra long string oh my gerd').toMatchTrimmedInlineSnapshot();
  9. /*
  10. The snapshot will be added inline like
  11. expect('extra long string oh my gerd').toMatchTrimmedInlineSnapshot(
  12. `"extra long"`
  13. );
  14. */
  15. });

expect.anything()

expect.anything()​匹配除​null​或 之外的任何内容​undefined​。可以在内部​toEqual​或​toBeCalledWith​代替文字值使用它。例如,如果要检查是否使用非空参数调用了模拟函数:

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

expect.any(constructor)

expect.any(constructor)​匹配使用给定构造函数创建的任何内容。可以在内部​toEqual​或​toBeCalledWith​代替文字值使用它。例如,如果要检查是否使用数字调用了模拟函数:

  1. function randocall(fn) {
  2. return fn(Math.floor(Math.random() * 6 + 1));
  3. }
  4. test('randocall calls its callback with a number', () => {
  5. const mock = jest.fn();
  6. randocall(mock);
  7. expect(mock).toBeCalledWith(expect.any(Number));
  8. });

expect.arrayContaining(array)

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

可以使用它代替文字值:

  • 在​toEqual​或​toBeCalledWith
  • 匹配​objectContaining​或​toMatchObject
  1. describe('arrayContaining', () => {
  2. const expected = ['Alice', 'Bob'];
  3. it('matches even if received contains additional elements', () => {
  4. expect(['Alice', 'Bob', 'Eve']).toEqual(expect.arrayContaining(expected));
  5. });
  6. it('does not match if received does not contain expected elements', () => {
  7. expect(['Bob', 'Eve']).not.toEqual(expect.arrayContaining(expected));
  8. });
  9. });
  1. describe('Beware of a misunderstanding! A sequence of dice rolls', () => {
  2. const expected = [1, 2, 3, 4, 5, 6];
  3. it('matches even with an unexpected number 7', () => {
  4. expect([4, 1, 6, 7, 3, 5, 2, 5, 4, 6]).toEqual(
  5. expect.arrayContaining(expected),
  6. );
  7. });
  8. it('does not match without an expected number 2', () => {
  9. expect([4, 1, 6, 7, 3, 5, 7, 5, 4, 6]).not.toEqual(
  10. expect.arrayContaining(expected),
  11. );
  12. });
  13. });

expect.assertions(number)

expect.assertions(number)​验证在测试期间调用了一定数量的断言。这在测试异步代码时通常很有用,以确保回调中的断言确实被调用。

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

  1. test('doAsync calls both callbacks', () => {
  2. expect.assertions(2);
  3. function callback1(data) {
  4. expect(data).toBeTruthy();
  5. }
  6. function callback2(data) {
  7. expect(data).toBeTruthy();
  8. }
  9. doAsync(callback1, callback2);
  10. });

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

expect.hasAssertions()

expect.hasAssertions()​验证在测试期间至少调用了一个断言。这在测试异步代码时通常很有用,以确保回调中的断言确实被调用。

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

  1. test('prepareState prepares a valid state', () => {
  2. expect.hasAssertions();
  3. prepareState(state => {
  4. expect(validateState(state)).toBeTruthy();
  5. });
  6. return waitOnState();
  7. });

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

expect.not.arrayContaining(array)

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

它是​expect.arrayContaining​的倒数​​。

  1. describe('not.arrayContaining', () => {
  2. const expected = ['Samantha'];
  3. it('matches if the actual array does not contain the expected elements', () => {
  4. expect(['Alice', 'Bob', 'Eve']).toEqual(
  5. expect.not.arrayContaining(expected),
  6. );
  7. });
  8. });

expect.not.objectContaining(object)

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

它是​expect.objectContaining的倒数​。

  1. describe('not.objectContaining', () => {
  2. const expected = {foo: 'bar'};
  3. it('matches if the actual object does not contain expected key: value pairs', () => {
  4. expect({bar: 'baz'}).toEqual(expect.not.objectContaining(expected));
  5. });
  6. });

expect.not.stringContaining(string)

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

它是​expect.stringContaining​的倒数​​。

  1. describe('not.stringContaining', () => {
  2. const expected = 'Hello world!';
  3. it('matches if the received value does not contain the expected substring', () => {
  4. expect('How are you?').toEqual(expect.not.stringContaining(expected));
  5. });
  6. });

expect.not.stringMatching(string | regexp)

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

它是​expect.stringMatching​的倒数。

  1. describe('not.stringMatching', () => {
  2. const expected = /Hello world!/;
  3. it('matches if the received value does not match the expected regex', () => {
  4. expect('How are you?').toEqual(expect.not.stringMatching(expected));
  5. });
  6. });

expect.objectContaining(object)

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

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

例如,假设我们希望​onPress​用一个​Event​对象调用一个函数,我们需要验证的是该事件是否具有​event.x​和​event.y​属性。我们可以这样做:

  1. test('onPress gets called with the right thing', () => {
  2. const onPress = jest.fn();
  3. simulatePresses(onPress);
  4. expect(onPress).toBeCalledWith(
  5. expect.objectContaining({
  6. x: expect.any(Number),
  7. y: expect.any(Number),
  8. }),
  9. );
  10. });

expect.stringContaining(string)

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

expect.stringMatching(string | regexp)

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

可以使用它代替文字值:

  • 在​toEqual​或​toBeCalledWith
  • 匹配一个元素 ​arrayContaining
  • 匹配​objectContaining​或​toMatchObject

这个例子还展示了如何嵌套多个非对称匹配器,​expect.stringMatching​在​expect.arrayContaining​.

  1. describe('stringMatching in arrayContaining', () => {
  2. const expected = [
  3. expect.stringMatching(/^Alic/),
  4. expect.stringMatching(/^[BR]ob/),
  5. ];
  6. it('matches even if received contains additional elements', () => {
  7. expect(['Alicia', 'Roberto', 'Evelina']).toEqual(
  8. expect.arrayContaining(expected),
  9. );
  10. });
  11. it('does not match if received does not contain expected elements', () => {
  12. expect(['Roberto', 'Evelina']).not.toEqual(
  13. expect.arrayContaining(expected),
  14. );
  15. });
  16. });

expect.addSnapshotSerializer(serializer)

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

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

  1. import serializer from 'my-serializer-module';
  2. expect.addSnapshotSerializer(serializer);
  3. // affects expect(value).toMatchSnapshot() assertions in the test file

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

  • 使依赖显式而不是隐式。
  • 避免了可能导致从create-react-app 中弹出的配置限制。

有关更多信息,请参阅配置 Jest

.not

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

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

.resolves

使用​.​​resolves​​​解开一个兑现承诺的价值,所以任何其他匹配可以链接。如果承诺被拒绝,则断言失败。

例如,此代码测试 ​promise ​是否已解析并且结果值为​'lemon'​:

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

请注意,由于仍在测试 promise,因此测试仍然是异步的。因此,需要通过返回未包装的断言来告诉 Jest 等待

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

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

.rejects

使用​.rejects​拆开包装,因此任何其他匹配可链接被拒绝承诺的理由。如果承诺被实现,则断言失败。

例如,此代码测试 ​Promise ​是否以 ​reason ​拒绝​'octopus'​:

  1. test('rejects to octopus', () => {
  2. // make sure to add a return statement
  3. return expect(Promise.reject(new Error('octopus'))).rejects.toThrow(
  4. 'octopus',
  5. );
  6. });

请注意,由于仍在测试 ​promise​,因此测试仍然是异步的。因此,需要通过返回未包装的断言来告诉 Jest 等待

或者,可以​async​/​await​与​.rejects​.

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

.toBe(value)

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

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

  1. const can = {
  2. name: 'pamplemousse',
  3. ounces: 12,
  4. };
  5. describe('the can', () => {
  6. test('has 12 ounces', () => {
  7. expect(can.ounces).toBe(12);
  8. });
  9. test('has a sophisticated name', () => {
  10. expect(can.name).toBe('pamplemousse');
  11. });
  12. });

不要​.toBe​与浮点数一起使用。例如,由于四舍五入,在 JavaScript0.2 + 0.1中并不严格等于0.3。如果有浮点数,请尝试​.toBeCloseTo​。

尽管​.toB​e匹配器检查引用标识,但如果断言失败,它会报告值的深度比较。如果属性之间的差异不能帮助你理解测试失败的原因,尤其是在报告很大的情况下,那么你可以将比较移到​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​函数并将其应用于所有可用的饮料。你可能想检查是否​drink​调用了 ​for 'lemon'​,而不是 ​for 'octopus'​,因为​'octopus'​味道真的很奇怪,为什么会有章鱼味的东西?你可以用这个测试套件做到这一点:

  1. function drinkAll(callback, flavour) {
  2. if (flavour !== 'octopus') {
  3. callback(flavour);
  4. }
  5. }
  6. describe('drinkAll', () => {
  7. test('drinks something lemon-flavoured', () => {
  8. const drink = jest.fn();
  9. drinkAll(drink, 'lemon');
  10. expect(drink).toHaveBeenCalled();
  11. });
  12. test('does not drink something octopus-flavoured', () => {
  13. const drink = jest.fn();
  14. drinkAll(drink, 'octopus');
  15. expect(drink).not.toHaveBeenCalled();
  16. });
  17. });

.toHaveBeenCalledTimes(number)

同样在别名下:​ .toBeCalledTimes(number)

使用​.toHaveBeenCalledTimes​以确保模拟功能得到调用次数确切数字。

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

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

.toHaveBeenCalledWith(arg1, arg2, ...)

同样在别名下:​ .toBeCalledWith()

使用​.toHaveBeenCalledWith​以确保模拟函数被调用的具体参数。

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

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

.toHaveBeenLastCalledWith(arg1, arg2, ...)

同样在别名下:​ .lastCalledWith(arg1, arg2, ...)

如果你有一个模拟函数,你可以​.toHaveBeenLastCalledWith​用来测试它最后被调用的参数。例如,假设你有一个​applyToAllFlavors(f)​适用f于一系列风味的函数,并且你希望确保在调用它时,它所操作的最后一种风味是​'mango'​。你可以写:

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

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

同样在别名下:​ .nthCalledWith(nthCall, arg1, arg2, ...)

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

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

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

.toHaveReturned()

同样在别名下:​ .toReturn()

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

  1. test('drinks returns', () => {
  2. const drink = jest.fn(() => true);
  3. drink();
  4. expect(drink).toHaveReturned();
  5. });

.toHaveReturnedTimes(number)

同样在别名下:​ .toReturnTimes(number)

使用​.toHaveReturnedTimes​以确保模拟函数返回成功(即未引发错误)的次一个确切的数字。任何抛出错误的模拟函数调用都不会计入函数返回的次数。

例如,假设你有一个​drink​返回​true​. 你可以写:

  1. test('drink returns twice', () => {
  2. const drink = jest.fn(() => true);
  3. drink();
  4. drink();
  5. expect(drink).toHaveReturnedTimes(2);
  6. });

.toHaveReturnedWith(value)

同样在别名下: ​.toReturnWith(value)

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

例如,假设你有一个​drink​返回已消费饮料名称的模拟。你可以写:

  1. test('drink returns La Croix', () => {
  2. const beverage = {name: 'La Croix'};
  3. const drink = jest.fn(beverage => beverage.name);
  4. drink(beverage);
  5. expect(drink).toHaveReturnedWith('La Croix');
  6. });

.toHaveLastReturnedWith(value)

同样在别名下:​ .lastReturnedWith(value)

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

例如,假设你有一个​drink​返回已消费饮料名称的模拟。你可以写:

  1. test('drink returns La Croix (Orange) last', () => {
  2. const beverage1 = {name: 'La Croix (Lemon)'};
  3. const beverage2 = {name: 'La Croix (Orange)'};
  4. const drink = jest.fn(beverage => beverage.name);
  5. drink(beverage1);
  6. drink(beverage2);
  7. expect(drink).toHaveLastReturnedWith('La Croix (Orange)');
  8. });

.toHaveNthReturnedWith(nthCall, value)

同样在别名下:​ .nthReturnedWith(nthCall, value)

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

例如,假设你有一个​drink​返回已消费饮料名称的模拟。你可以写:

  1. test('drink returns expected nth calls', () => {
  2. const beverage1 = {name: 'La Croix (Lemon)'};
  3. const beverage2 = {name: 'La Croix (Orange)'};
  4. const drink = jest.fn(beverage => beverage.name);
  5. drink(beverage1);
  6. drink(beverage2);
  7. expect(drink).toHaveNthReturnedWith(1, 'La Croix (Lemon)');
  8. expect(drink).toHaveNthReturnedWith(2, 'La Croix (Orange)');
  9. });

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

.toHaveLength(number)

使用​.toHaveLength​检查的对象有一个​.length​属性,并将其设置为某一数值。

这对于检查数组或字符串大小特别有用。

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

.toHaveProperty(keyPath, value?)

使用​.toHaveProperty​检查,如果在提供的参考属性​keyPath​存在的对象。为了检查对象中深度嵌套的属性,你可以使用点表示法或包含用于深度引用的 ​keyPath ​的数组。

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

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

  1. // Object containing house features to be tested
  2. const houseForSale = {
  3. bath: true,
  4. bedrooms: 4,
  5. kitchen: {
  6. amenities: ['oven', 'stove', 'washer'],
  7. area: 20,
  8. wallColor: 'white',
  9. 'nice.oven': true,
  10. },
  11. 'ceiling.height': 2,
  12. };
  13. test('this house has my desired features', () => {
  14. // Example Referencing
  15. expect(houseForSale).toHaveProperty('bath');
  16. expect(houseForSale).toHaveProperty('bedrooms', 4);
  17. expect(houseForSale).not.toHaveProperty('pool');
  18. // Deep referencing using dot notation
  19. expect(houseForSale).toHaveProperty('kitchen.area', 20);
  20. expect(houseForSale).toHaveProperty('kitchen.amenities', [
  21. 'oven',
  22. 'stove',
  23. 'washer',
  24. ]);
  25. expect(houseForSale).not.toHaveProperty('kitchen.open');
  26. // Deep referencing using an array containing the keyPath
  27. expect(houseForSale).toHaveProperty(['kitchen', 'area'], 20);
  28. expect(houseForSale).toHaveProperty(
  29. ['kitchen', 'amenities'],
  30. ['oven', 'stove', 'washer'],
  31. );
  32. expect(houseForSale).toHaveProperty(['kitchen', 'amenities', 0], 'oven');
  33. expect(houseForSale).toHaveProperty(['kitchen', 'nice.oven']);
  34. expect(houseForSale).not.toHaveProperty(['kitchen', 'open']);
  35. // Referencing keys with dot in the key itself
  36. expect(houseForSale).toHaveProperty(['ceiling.height'], 'tall');
  37. });

.toBeCloseTo(number, numDigits?)

使用​toBeCloseTo​浮点数的近似相等比较。

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

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

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

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

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

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

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

.toBeDefined()

使用​.toBeDefined​检查一个变量是不是不确定的。例如,如果你想检查一个函数是否​fetchNewFlavorIdea()​返回了一些东西,你可以这样写:

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

可以编写​expect(fetchNewFlavorIdea()).not.toBe(undefined)​,但最好避免undefined在代码中直接引用。

.toBeFalsy()

使用​.toBeFalsy​时,你不关心的值是什么,你要确保一个值是在布尔上下文假的。例如,假设你有一些如下所示的应用程序代码:

  1. drinkSomeLaCroix();
  2. if (!getErrors()) {
  3. drinkMoreLaCroix();
  4. }

你可能并不关心​getErrors​返回什么,特别是 - 它可能返回​false​、​null​、 或​0​,而你的代码仍然可以工作。所以如果你想在喝了一些 La Croix 后测试有没有错误,你可以写:

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

在JavaScript中,有六个falsy值:false,0,'',null,undefined,和NaN。其他一切都是真实的。

.toBeGreaterThan(number | bigint)

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

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

.toBeGreaterThanOrEqual(number | bigint)

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

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

.toBeLessThan(number | bigint)

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

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

.toBeLessThanOrEqual(number | bigint)

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

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

.toBeInstanceOf(Class)

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

  1. class A {}
  2. expect(new A()).toBeInstanceOf(A);
  3. expect(() => {}).toBeInstanceOf(Function);
  4. expect(new A()).toBeInstanceOf(Function); // throws

.toBeNull()

.​toBeNull()​与相同​.toBe(null)​但错误消息更好一些。所以​.toBeNull()​当你想检查某些东西是否为空时使用。

  1. function bloop() {
  2. return null;
  3. }
  4. test('bloop returns null', () => {
  5. expect(bloop()).toBeNull();
  6. });

.toBeTruthy()

使用​.toBeTruthy​时,你不关心的值是什么,你要确保一个值在布尔环境是真实的。例如,假设你有一些如下所示的应用程序代码:

  1. drinkSomeLaCroix();
  2. if (thirstInfo()) {
  3. drinkMoreLaCroix();
  4. }

你可能不在乎​thirstInfo​返回什么,​特别是​它可能返回true或者一个复杂的对象,并且你的代码仍然可以工作。所以如果你想测试在喝了一些 ​La Croix​ 后​thirstInfo​是否真实,你可以写:

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

在JavaScript中,有六个falsy值:​false​,​0​,​''​,​null​,​undefined​,和​NaN​。其他一切都是真实的。

.toBeUndefined()

使用​.toBeUndefined​检查变量不确定。例如,如果你想检查一个函数​bestDrinkForFlavor(flavor)​返回​undefined​的​'octopus'​味道,因为没有好的​octopus-flavored​饮料:

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

你可以编写​expect(bestDrinkForFlavor('octopus')).toBe(undefined)​,但最好避免​undefined​在代码中直接引用。

.toBeNaN()

.toBeNaN​在检查值时使用​NaN​。

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

.toContain(item)

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

例如,如果​getAllFlavors()​返回一个风味数组,并且你想确保其中包含该数组,​lime​则可以编写:

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

.toContainEqual(item)

使用​.toContainEqual​时要检查是否具有特定结构和值的项目包含在一个阵列。为了测试数组中的项目,这个匹配器递归地检查所有字段的相等性,而不是检查对象身份。

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

.toEqual(value)

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

例如,​.toEqual​和​.toBe​不同的表现在这个测试套件,所以所有的测试都通过了:

  1. const can1 = {
  2. flavor: 'grapefruit',
  3. ounces: 12,
  4. };
  5. const can2 = {
  6. flavor: 'grapefruit',
  7. ounces: 12,
  8. };
  9. describe('the La Croix cans on my desk', () => {
  10. test('have all the same properties', () => {
  11. expect(can1).toEqual(can2);
  12. });
  13. test('are not the exact same can', () => {
  14. expect(can1).not.toBe(can2);
  15. });
  16. });
注意:​.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​应该在某个地方。可以使用以下方法进行测试:

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

这个匹配器还接受一个字符串,它将尝试匹配:

  1. describe('grapefruits are healthy', () => {
  2. test('grapefruits are a fruit', () => {
  3. expect('grapefruits').toMatch('fruit');
  4. });
  5. });

.toMatchObject(object)

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

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

可以将属性与值或匹配器进行匹配。

  1. const houseForSale = {
  2. bath: true,
  3. bedrooms: 4,
  4. kitchen: {
  5. amenities: ['oven', 'stove', 'washer'],
  6. area: 20,
  7. wallColor: 'white',
  8. },
  9. };
  10. const desiredHouse = {
  11. bath: true,
  12. kitchen: {
  13. amenities: ['oven', 'stove', 'washer'],
  14. wallColor: expect.stringMatching(/white|yellow/),
  15. },
  16. };
  17. test('the house has my desired features', () => {
  18. expect(houseForSale).toMatchObject(desiredHouse);
  19. });
  1. describe('toMatchObject applied to arrays', () => {
  2. test('the number of elements must match exactly', () => {
  3. expect([{foo: 'bar'}, {baz: 1}]).toMatchObject([{foo: 'bar'}, {baz: 1}]);
  4. });
  5. test('.toMatchObject is called for each elements, so extra object properties are okay', () => {
  6. expect([{foo: 'bar'}, {baz: 1, extra: 'quux'}]).toMatchObject([
  7. {foo: 'bar'},
  8. {baz: 1},
  9. ]);
  10. });
  11. });

.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​。
  1. class LaCroix {
  2. constructor(flavor) {
  3. this.flavor = flavor;
  4. }
  5. }
  6. describe('the La Croix cans on my desk', () => {
  7. test('are not semantically the same', () => {
  8. expect(new LaCroix('lemon')).toEqual({flavor: 'lemon'});
  9. expect(new LaCroix('lemon')).not.toStrictEqual({flavor: 'lemon'});
  10. });
  11. });

.toThrow(error?)

同样在别名下:​ .toThrowError(error?)

使用​.toThrow​测试,当它被称为函数抛出。例如,如果我们要测试​drinkFlavor('octopus')​投掷,因为章鱼的味道太难喝了,我们可以这样写:

  1. test('throws on octopus', () => {
  2. expect(() => {
  3. drinkFlavor('octopus');
  4. }).toThrow();
  5. });
注意:必须将代码包裹在一个函数中,否则无法捕获错误,断言失败。

可以提供一个可选参数来测试是否抛出了特定错误:

  • 正则表达式:错误消息与模式匹配
  • 字符串:错误消息包括子字符串
  • 错误对象:错误消息等于对象的消息属性
  • 错误类:错误对象是类的实例

例如,假设它​drinkFlavor​是这样编码的:

  1. function drinkFlavor(flavor) {
  2. if (flavor == 'octopus') {
  3. throw new DisgustingFlavorError('yuck, octopus flavor');
  4. }
  5. // Do some other stuff
  6. }

我们可以通过几种方式测试这个错误是否被抛出:

  1. test('throws on octopus', () => {
  2. function drinkOctopus() {
  3. drinkFlavor('octopus');
  4. }
  5. // Test that the error message says "yuck" somewhere: these are equivalent
  6. expect(drinkOctopus).toThrowError(/yuck/);
  7. expect(drinkOctopus).toThrowError('yuck');
  8. // Test the exact error message
  9. expect(drinkOctopus).toThrowError(/^yuck, octopus flavor$/);
  10. expect(drinkOctopus).toThrowError(new Error('yuck, octopus flavor'));
  11. // Test that we get a DisgustingFlavorError
  12. expect(drinkOctopus).toThrowError(DisgustingFlavorError);
  13. });

.toThrowErrorMatchingSnapshot(hint?)

使用​.toThrowErrorMatchingSnapshot​测试一个函数抛出匹配最新的快照时,它被称为一个错误。

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

例如,假设你有一个​drinkFlavor​函数,该函数在风味为 时抛出​'octopus'​,其编码如下:

  1. function drinkFlavor(flavor) {
  2. if (flavor == 'octopus') {
  3. throw new DisgustingFlavorError('yuck, octopus flavor');
  4. }
  5. // Do some other stuff
  6. }

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

  1. test('throws on octopus', () => {
  2. function drinkOctopus() {
  3. drinkFlavor('octopus');
  4. }
  5. expect(drinkOctopus).toThrowErrorMatchingSnapshot();
  6. });

它将生成以下快照:

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

查看React Tree Snapshot Testing以获取有关快照测试的更多信息。

.toThrowErrorMatchingInlineSnapshot(inlineSnapshot)

使用​.toThrowErrorMatchingInlineSnapshot​测试一个函数抛出匹配最新的快照时,它被称为一个错误。

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

查看内联快照部分了解更多信息。


以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号