メインコンテンツへスキップ
Version: Next

Expect

テストを作成する時に、値が特定の条件に合致することを確認する必要がよくあるでしょう。 expect によって様々な事柄を検証するための数多くの「マッチャ」を利用することができます。

tip

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

info

このページの TypeScript の例は、次のように Jest の API を明示的にインポートした場合にのみ動作します。

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

TypeScript で Jest をセットアップする方法の詳細については、Getting Started ガイドを参照してください。

リファレンス


Expect

expect(value)

expect は値をテストしたい時に毎回使用する関数です。 expect のみを呼び出すということはほとんどありません。 代わりに、 値について何らかの事をアサートする"マッチャ"関数とともにexpect を使用することでしょう。

この事は例を見れば簡単に理解できます。 'grapefruit'という文字列を返すはずのbestLaCroixFlavor()メソッドがあるとしましょう。 以下のようにテストするでしょう:

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

このケースでは、 toBeがマッチャ関数です。 様々な事をテストするのを手助けする数多くの異なるマッチャ関数があり、以下にまとめられています。

expectへの引数はコードが生成する値であるべきであり、いかなるマッチャへの引数は正解の値であるべきです。 それらを混同して使用すれば、テストは動作するものの、失敗したテストから出力されるエラーメッセージはおかしなものになります。

修飾子

.not

何かをテストする方法が分かっているなら、 .notによってその反対の事をテストできます。 例えば以下のコードでは、ラクロワ飲料で一番美味しいのはココナッツ味ではないことをテストでします。

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

.resolves

追加のマッチャをチェーンするためにに完了したpromiseの値を取り出すにはresolvesを使用して下さい。 promiseがrejectされた場合はアサーションは失敗します。

例えば、以下のコードではpromiseが完了した結果の値が'lemon'であることをテストします:

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

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

追加のマッチャをチェーンするためににrejectされたpromiseの理由を取り出すには .rejectsを使用して下さい。 promiseが完了した場合はアサーションは失敗します。

たとえば、このコードは Promise が 'octopus' という理由で reject されたことをテストします。

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

Promise をテストしているため、テストはまだ非同期です。 このために、ラップされていないアサーションを返すことで、Jest に処理が完了するまで待つように伝える必要があるのです。

また、async/await.rejectsと組み合わせて使うことができます。

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

Matchers

.toBe(value)

プリミティブ値を比較したり、オブジェクトインスタンスの参照IDを確認したりするには、 .toBe を使用します。 It calls Object.is to compare values, which is even better for testing than === strict equality operator.

例えば以下のコードでは can オブジェクトのいくつかのプロパティを検証します。

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

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

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

浮動小数点数に .toBe を使用しないでください。 例えば、JavaScriptでは数値の丸めによって0.2 + 0.10.3は厳密には等価ではありません。 浮動小数点がある場合は、代わりに.toBeCloseToを使用してください。

.toBe マッチャー は 参照IDをチェックしますが、アサーションが失敗した場合、 値の再帰的な比較を** 報告します**。 特にレポートが大きい場合には、プロパティ間の差分は、テストが失敗する理原因を解明することに寄与しません。 そうすると、比較処理を expect 関数の中に移すことでしょう 例えば、要素が同じインスタンスであるかどうかをアサートするには、次のようにします。

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

.toHaveBeenCalled()

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

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? このテストスイートでテストすることができます:

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)

モック関数が期待した回数だけ呼ばれたことを確認するには.toHaveBeenCalledTimes を使用して下さい。

例えばdrink関数を引数に取って渡された飲み物の配列に適用する 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, ...)

モック関数が特定の引数を与えられて呼び出されたことを確認するには .toHaveBeenCalledWith を使用して下さい。 The arguments are checked with the same algorithm that .toEqual uses.

例えば 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, ...)

モック関数がある場合は .toHaveBeenLastCalledWithを使用して、最後の呼び出しがどんな引数を渡されたかをテストすることができます。 例えば 複数の風味に対して関数fを適用する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, ....)

あるモック関数があるとき、.toHaveReturned を使用すると、モック関数が正しく (つまり、例外が発生せずに) 変えることをテストできます。 たとえば、true を返すモック関数 drink があるとすると、テストは次のように書くことができます。 以下のようにテストコードを書くことができます。

test('drink は n 回目の呼び出しで期待した値を返す', () => {
const beverage1 = {name: 'La Croix (レモン)'};
const beverage2 = {name: 'La Croix (オレンジ)'};
const drink = jest.fn(beverage => beverage.name);

drink(beverage1);
drink(beverage2);

expect(drink).toHaveNthReturnedWith(1, 'La Croix (レモン)');
expect(drink).toHaveNthReturnedWith(2, 'La Croix (オレンジ)');
});
note

The nth argument must be positive integer starting from 1.

.toHaveReturned()

あるモック関数があるとき、.toHaveReturned を使用すると、モック関数が正しく (つまり、例外が発生せずに) 変えることをテストできます。 たとえば、true を返すモック関数 drink があるとすると、テストは次のように書くことができます。 以下のようにテストコードを書くことができます。

test('drinkEach drinks each drink', () => {
const drink = jest.fn();
drinkEach(drink, ['レモン', 'タコ']);
expect(drink).toHaveBeenNthCalledWith(1, 'レモン');
expect(drink).toHaveBeenNthCalledWith(2, 'タコ');
});

.toHaveReturnedTimes(number)

モック関数がちょうど指定した回数だけ正しく (つまり、例外が発生せずに) 返ったことを確認するには、.toHaveReturnedTimes を使用してください。 例外が発生したモック関数の呼び出しは、関数の返した回数としてカウントされません。

たとえば、true を返すモック関数 drink があるとすると、テストは次のように書くことができます。 以下のようにテストコードを書くことができます。

test('drinks は return する', () => {
const drink = jest.fn(() => true);

drink();

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

.toHaveReturnedWith(value)

モック関数が特定の値を返すことを確認するには、. toHaveReturnedWith を使用してください。

たとえば、飲まれた飲み物 (beverage) の名前を返すモック関数 drink があるとすると、テストは次のように書くことができます。 以下のようにテストコードを書くことができます。

test('drink は2回正しく return する', () => {
const drink = jest.fn(() => true);

drink();
drink();

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

.toHaveLastReturnedWith(value)

モック関数が最後に返した値が特定の値であるかどうかをテストするには、.toHaveLastReturnedWith を使用してください。 モック関数の最後の呼び出しで例外が発生した場合、期待した値としてどんな値を指定したとしても、このマッチャは無条件に失敗します。

たとえば、飲まれた飲み物 (beverage) の名前を返すモック関数 drink があるとすると、テストは次のように書くことができます。 以下のようにテストコードを書くことができます。

test('drink は La Croix を返す', () => {
const beverage = {name: 'La Croix'};
const drink = jest.fn(beverage => beverage.name);

drink(beverage);

expect(drink).toHaveReturnedWith('La Croix');
});

.toHaveNthReturnedWith(nthCall, value)

モック関数が n 回目に返した値が特定の値であるかどうかをテストするには、.toHaveNthReturnedWith を使用してください。 モック関数の n 回目の呼び出しで例外が発生した場合、期待した値としてどんな値を指定したとしても、このマッチャは無条件に失敗します。

たとえば、飲まれた飲み物 (beverage) の名前を返すモック関数 drink があるとすると、テストは次のように書くことができます。 以下のようにテストコードを書くことができます。

test('drink は最後に La Croix (Orange) を return する', () => {
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)');
});
note

The nth argument must be positive integer starting from 1.

.toHaveLength(number)

オブジェクトが.lengthプロパティを持ち、特定の数値であるかを確認するには、.toHaveLength を使用して下さい。

配列や文字列のサイズを確認するのに特に便利です。

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

.toHaveProperty(keyPath, value?)

オブジェクトの指定された参照keyPathのプロパティが存在するかを確認するには、.toHaveProperty を使用して下さい。 オブジェクト内で深くネストされたプロパティをチェックするには、 深い階層を参照するために、 ドット表記や keyPath を含む配列を使用することができます。

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 を利用しています。

// 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 では、浮動小数点数を近似的な等価性で評価します。

オプションのnumDigits 引数は小数点以下の桁数の上限を設定します。 デフォルト値 2の場合、テスト条件は Math.abs(expected - received) < 0.005以内 (つまり、 10 ** -2 / 2)となります。

なぜなら、10 進数(ベース 10)での計算は、限られた精度の二進数(ベース 2)での表現による丸め誤差を含んでいることがよくあるからdす。 例えば、このテストは失敗します:

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

変数が undefined ではないことを検証するには、.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がどんなものを返すかは特に気にしないでしょう - falsenull、あるいは 0を返すかもしれませんが、それでもコードは動作します。 だからラクロワ飲料を飲んだ後でエラーが無いことをテストしたければ、このように書くことができます:

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

JavaScriptでは、偽と類推される6つの値があります: false0''nullundefined、 そして NaNです。 他の全ては真と類推されます。

.toBeGreaterThan(number | bigint)

toBeGreaterThan により、 実際値 > 期待値 の条件でnumber型またはbigint 型の数値を比較します。 例えば、 ouncesPerCan() が 10 オンスより大きい値を返すことをテストします。

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

.toBeGreaterThanOrEqual(number | bigint)

toBeGreaterThanOrEqual を使用して、 実際値 >= 期待値 の条件でnumber型またはbigint 型の数値を比較します。 例えば、 ouncesPerCan() が12 オンス以上の値を返すことをテストします。

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

.toBeLessThan(number | bigint)

toBeLessThan を使用して、実際値 < 期待値 の条件でnumber型またはbigint 型の数値を比較します。 例えば、 ouncesPerCan() が 20 オンス未満の値を返すことをテストします。

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

.toBeLessThanOrEqual(number | bigint)

toBeLessThanOrEqual を使用して、 実際値 <= 期待値 の条件でnumber型またはbigint 型の数値を比較します。 例えば、 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)と同じですが、エラーメッセージが少し分かりやすいものになっています。 そのため何かがnullであることを確認したい場合は .toBeNull()を使用して下さい。

function bloop() {
return null;
}

test('bloop returns null', () => {
expect(bloop()).toBeNull();
});

.toBeTruthy()

値がどのようなものかを気にせず、真偽値のコンテクストの中で値が真であることを確認したい場合は.toBeTruthy を使用して下さい。 例えば、以下のようなアプリケーションコードがあったとします:

drinkSomeLaCroix();
if (thirstInfo()) {
drinkMoreLaCroix();
}

thirstInfoがどんなものを返すかは特に気にしないでしょう - trueもしくは複雑な値を返すかもしれませんが、それでもコードは動作します。 だからラクロワ飲料を飲んだ後にthirstInfoが真(またはそう類推される値) を返すことをテストするには、次のように書くことができます:

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

JavaScriptでは、偽と類推される6つの値があります: false0''nullundefined、 そして NaNです。 他の全ては真と類推されます。

.toBeUndefined()

関数が呼ばれた際にエラーを投げることを確認するには.toThrow を使用して下さい。 例えば、タコ味なんて気持ち悪すぎて飲めないのでdrinkFlavor('octopus') が例外を投げることをテストしたい場合、次のように書くことができます:

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

expect(bestDrinkForFlavor('octopus')).toBe(undefined)とも書くことができますが、undefinedを直接コード内で参照するのは避けたほうが実務上良いでしょう。

.toBeNaN()

値が NaNであるかを検証するには、 .toBeNaN を使用してください。

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

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

.toContainEqual(item)

特定の構造と値を持つ要素が配列に含まれていることをチェックしたい場合は.toContainEqualを使用して下さい。 配列中のアイテムをテストするために、このマッチャはオブジェクトIDではなく、再帰的に全てのフィールドの等価性を確認します。

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

.toEqual(value)

オブジェクトインスタンスのすべてのプロパティを再帰的に等しいかの検証 (「深い」等価性としても知られています)には、 .toEqual を使用します。 It calls Object.is to compare primitive values, which is even better for testing than === strict equality operator.

例えば、 .toEqual.toBeは以下のテストスイートで異なる振る舞いをするので、全てのテストがパスします:

const can1 = {
flavor: 'grapefruit',
ounces: 12,
};
const can2 = {
flavor: 'grapefruit',
ounces: 12,
};

describe('the La Croix cans on my desk', () => {
test('have all the same properties', () => {
expect(can1).toEqual(can2);
});
test('are not the exact same can', () => {
expect(can1).not.toBe(can2);
});
});
tip

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

info

.toEqual won't perform a deep equality check for two errors. エラーオブジェクトの messageプロパティのみを等価性の比較対象とします。 エラーに対するテストは .toThrowマッチャの使用をお勧めします。

特にレポートが大きい場合には、プロパティ間の差分は、テストが失敗する理原因を解明することに寄与しません。 例えば、バッファに同じ内容が含まれているかどうかをアサートするには、 Buffer クラスの equals メソッドを使用して下さい。

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

.toMatch(regexp | string)

文字列が正規表現と一致することを確認するには.toMatch を使用して下さい。

例えば、essayOnTheBestFlavor() がどのようなものか正確には分からないけれども本当に長い文字列を返すこと、そして grapefruitという文字列がその中のどこかに含まれるべきであるということを知っているとしましょう。 以下のコードでテストできます:

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

このマッチャは正規表現と照合する対象に文字列も取ることができます:

describe('grapefruits are healthy', () => {
test('grapefruits are a fruit', () => {
expect('grapefruits').toMatch('fruit');
});
});

.toMatchObject(object)

JavaScript オブジェクトが、あるオブジェクトのプロパティのサブセットに一致することを確認するには.ToMatchObject を使用して下さい。 期待されるオブジェクトに含まれないプロパティを含む引数のオブジェクトについても一致します。

オブジェクトの配列を渡すこともでき、その場合はメソッドは期待する配列の対応するオブジェクトと引数の配列の各オブジェクトが( 上述のtoMatchObjectと同じ意味で) 一致する場合のみ真を返します。 このAPIは引数の配列が余分な要素を持つことを受容する arrayContainingとは反対に、2つの配列がその数で一致することを確認するのに便利です。

プロパティは値またはマッチャでマッチすることができます。

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

この API は最も最近のスナップショットと一致することを確認します。 詳細については the Snapshot Testing guide を確認して下さい。

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.

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)

値が最も新しいスナップショットにマッチすることを保証します。

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

詳しい情報については、インラインスナップショットのセクションを参照してください。

.toStrictEqual(value)

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

Differences from .toEqual:

  • keys with undefined properties are checked, e.g. {a: undefined, b: 2} will not equal {b: 2};
  • undefined items are taken into account, e.g. [2] will not equal [2, undefined];
  • array sparseness is checked, e.g. [, 1] will not equal [undefined, 1];
  • 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('レモン')).toEqual({flavor: 'レモン'});
expect(new LaCroix('レモン')).not.toStrictEqual({flavor: 'レモン'});
});
});

.toThrow(error?)

関数が呼ばれた際にエラーを投げることを確認するには.toThrow を使用して下さい。 例えば、 関数bestDrinkForFlavor(flavor)'octopus'味が与えられた時にundefinedを返すことを確認したいとしましょう。 タコ味の美味しい飲み物なんてありませんから:

test('throws on octopus', () => {
expect(() => {
drinkFlavor('octopus');
}).toThrow();
});
tip

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
  • error object: error message is equal to the message property of the object
  • error class: error object is instance of class

例えば、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 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を使用して下さい。

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.

例えば、 風味が'octopus'ならば必ずエラーを投げる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');
}

expect(drinkOctopus).toThrowErrorMatchingSnapshot();
});

そして次のようなスナップショットを生成します:

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

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

.toThrowErrorMatchingInlineSnapshot(inlineSnapshot)

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

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.

詳しい情報については、インラインスナップショットのセクションを参照してください。

Asymmetric Matchers

expect.anything()

expect.anything() は、null または undefined を除くものすべてに一致します。 You can use it inside toEqual or toHaveBeenCalledWith instead of a literal value. 例えば、モック関数がnullでない引数を与えられて呼び出されたことを確認するには:

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) 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. 例えば、モック関数が数字の引数を与えられて呼び出されたことを確認するには:

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) は受け取った配列が期待される配列の要素全てを含む場合に一致します。 つまり受け取った配列は期待される配列を 包含 するということです。 したがって受け取る配列が期待される配列に含まれない要素を含んでいても一致します。

以下のケースでリテラル値の代わりに使用できます:

  • in toEqual or toHaveBeenCalledWith
  • 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) matches a received array which does not contain all of the elements in the expected 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.closeTo(number, numDigits?)

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 引数は小数点以下の桁数の上限を設定します。 For the default value 2, the test criterion is Math.abs(expected - received) < 0.005 (that is, 10 ** -2 / 2).

例えば、このテストは小数点以下5桁の精度で合格します。

test('compare float in object properties', () => {
expect({
title: '0.1 + 0.2',
sum: 0.1 + 0.2,
}).toEqual({
title: '0.1 + 0.2',
sum: expect.closeTo(0.3, 5),
});
});

expect.objectContaining(object)

expect.objectContaining(object) は期待されたプロパティに再帰的に一致する、いかなる受け取ったオブジェクトにも一致します。 つまり期待されるオブジェクトは受け取ったオブジェクトの 一部分 であるということです。 Therefore, it matches a received object which contains properties that are present in the expected object.

期待されるオブジェクトのプロパティにリテラル値を設定する代わりに、expect.anything()などのマッチャを使用することができます。

例えば、onPress関数がEvent オブジェクトと共に呼ばれ、eventが event.xevent.y プロパティを持っていることだけ確認できれば良いと考えましょう。 以下のようにできます:

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.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) matches the received value if it is a string that contains the exact expected 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 の逆です。

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) matches the received value if it is a string that matches the expected string or regular expression.

以下のケースでリテラル値の代わりに使用できます:

  • in toEqual or toHaveBeenCalledWith
  • to match an element in arrayContaining
  • to match a property in objectContaining or toMatchObject

この例ではexpect.arrayContaining内のexpect.stringMatching によって、複数の非対称なマッチャをネストする方法も示します。

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) 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 の逆です。

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) はテスト中に特定の数だけアサーションが呼び出されたことを確認します。 非同期のコードをテストにおいて、コールバック中のアサーションが実際に呼ばれたことを確認する際にしばしば便利です。

例えば、 callback1callback2の2つのコールバックを受けとるdoAsync関数があったとしたら、その関数は未知の順序で両方を呼び出します。 以下のコードでテストできます:

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()はテスト中で少なくとも1回はアサーションが呼び出されたことを確認します。 非同期のコードをテストにおいて、コールバック中のアサーションが実際に呼ばれたことを確認する際にしばしば便利です。

例えば状態を取り扱ういくつかの関数があったとしましょう。 prepareState は状態オブジェクトとともにコールバックを呼び出し、validateState はその状態オブジェクトを確認し、 waitOnStateprepareState のコールバックが完了するまで待つpromiseを返します。 以下のコードでテストできます:

est('prepareState prepares a valid state', () => {
expect.hasAssertions();
prepareState(state => {
expect(validateState(state)).toBeTruthy();
});
return waitOnState();
});

expect.hasAssertions()prepareStateのコールバックが実際に呼ばれたことを確認します。

Extend Utilities

expect.addEqualityTesters(testers)

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

Custom equality testers API

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

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

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

this.equals(a, b, customTesters?)

2つのオブジェクトが同じ値を(再帰的に) 持つ場合に trueを返す深い等価関数です。 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

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.

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.

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

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.

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]);
note

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を使用して、アプリケーション独自のデータ構造をフォーマットするモジュールを追加することができます。

個々のテストファイルにおいては、JavaScriptに組み込みの型やReactの要素のデフォルトのスナップショットのシリアライザよりもsnapshotSerializers設定で追加されたモジュールが優先され、それらの全てのモジュールより(このAPIで) 追加されたモジュールは優先されます。 最後に追加されたモジュールが最初に確認されるモジュールになります。

import serializer from 'my-serializer-module';
expect.addSnapshotSerializer(serializer);

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

snapshotSerializer 設定に追加する代わりに、個々のテストファイルにスナップショットシリアライザを追加する場合:

  • You make the dependency explicit instead of implicit.
  • You avoid limits to configuration that might cause you to eject from create-react-app.

詳細については configuring Jest を参照してください。

expect.extend(matchers)

Jestに独自のマッチャを追加したい場合は expect.extendを使用します。 たとえば、数値に関するユーティリティのライブラリをテストしていて、ある数値が他の数値の特定の範囲内に現れることを頻繁にアサートしているとします。 それを toBeWithinRange のマッチャーに抽象化できます:

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 {};
tip

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 {}.

tip

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 を返すため、返り値を await する必要があります。 マッチャの一例を使って、使い方を見てみましょう。 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();
});

Custom Matchers API

マッチャは、2つのキーを持つオブジェクト (またはオブジェクトのプロミス) を返さなければなりません。 passキーはマッチャの条件に合致するかどうかを示し、 messageキーは失敗した場合にエラーメッセージを返す引数なしの関数を提供します。 したがって、passが偽なら、 messageexpect(x).yourMatcher()が失敗した場合のエラーメッセージを返す必要があります。 passが真だった場合、 messageexpect(x).not.yourMatcher()が失敗した場合のエラーメッセージを返す必要があります。

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: () => '',
};
},
});

マッチャがアサーションを反転させる否定の修飾子 .notを付けて呼ばれたかどうかを示す真偽値で、明確で正しいマッチャのヒントを表示することに利用されます(サンプルコードを参照)。

this.isNot

明確で正しいマッチャのヒントを表示するための文字列です:

this.promise

2つのオブジェクトが同じ値を(再帰的に) 持つ場合に trueを返す深い等価関数です。

  • 'rejects' if matcher was called with the promise .rejects modifier
  • 'resolves' if matcher was called with the promise .resolves modifier
  • '' if matcher was not called with a promise modifier

this.equals(a, b, customTesters?)

2つのオブジェクトが同じ値を(再帰的に) 持つ場合に trueを返す深い等価関数です。 It optionally takes a list of custom equality testers to apply to the deep equality checks (see this.customTesters below).

this.expand

このマッチャが expand オプション付きで呼び出されたことを示す真偽値です。 Jestが--expandフラグ付きで呼びされた場合、Jestが全ての差分とエラーを表示することを期待されているかを確認するのに、this.expandが利用できます。

this.utils

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

最も有用なものにエラーメッセージを見やすくフォーマットする matcherHintprintExpected そして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
? () =>
// 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};
},
});

上記のコードはこのような出力をします:

  expect(received).toBe(expected)

Expected value to be (using Object.is):
"banana"
Received:
"apple"

アサーションに失敗した場合、エラーメッセージは利用者がその問題を迅速に解決できるようになるべく多くのシグナルを与えるものであるべきです。 独自アサーションの利用者が良い開発体験を得られるよう正確なエラーメッセージを作成する必要があります。

this.customTesters

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

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

.toMatchTrimedSnapshot(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"`;
*/

Jest needs additional context information to find where the custom inline snapshot matcher was used to update the snapshots properly. ただし、インラインスナップショットは常に最初の引数に追加しようとします。 最初の引数がプロパティのマッチャである場合は、2番目の引数に追加しようとします。

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

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

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"`);
});

Serializable properties

SERIALIZABLE_PROPERTIES

Serializable properties is a set of properties that are considered serializable by Jest. This set is used to determine if a property should be serializable or not. If an object has a property that is not in this set, it is considered not serializable and will not be printed in error messages.

You can add your own properties to this set to make sure that your objects are printed correctly. For example, if you have a Volume class, and you want to make sure that only the amount and unit properties are printed, you can add it to SERIALIZABLE_PROPERTIES:

import {SERIALIZABLE_PROPERTIES} from 'jest-matcher-utils';

class Volume {
constructor(amount, unit) {
this.amount = amount;
this.unit = unit;
}

get label() {
throw new Error('Not implemented');
}
}

Volume.prototype[SERIALIZABLE_PROPERTIES] = ['amount', 'unit'];

expect(new Volume(1, 'L')).toEqual(new Volume(10, 'L'));

This will print only the amount and unit properties in the error message, ignoring the label property.

expect(received).toEqual(expected) // deep equality

Expected: {"amount": 10, "unit": "L"}
Received: {"amount": 1, "unit": "L"}