expect
以下の型シグネチャで使用される型は次の通りです。
type Awaitable<T> = T | PromiseLike<T>;
expect
はアサーションを作成するために使用されます。このコンテキストにおいて、アサーション
とは、ステートメントの正しさを検証するために呼び出すことができる関数のことです。Vitest はデフォルトで chai
のアサーションを提供し、chai
を基盤として構築された Jest
互換のアサーションも提供します。
例えば、以下のコードは input
の値が 2
と等しいことを検証します。等しくない場合、アサーションはエラーをスローし、テストが失敗します。
import { expect } from 'vitest';
const input = Math.sqrt(4);
expect(input).to.equal(2); // chai API
expect(input).toBe(2); // jest API
厳密に言えば、この例では test
関数を使用していないため、コンソールには Vitest の出力ではなく Node.js のエラーが表示されます。test
についてより詳しく知りたい場合は、テスト API リファレンス を参照してください。
また、expect
は後述するマッチャー関数などに静的にアクセスすることもできます。
WARNING
expect
は、式に型エラーがない場合、型のテストには影響を与えません。Vitest を 型チェッカー として使用したい場合は、expectTypeOf
または assertType
を使用してください。
soft
- 型:
ExpectStatic & (actual: any) => Assertions
expect.soft
は expect
と同様に機能しますが、アサーションが失敗した場合にテストの実行を終了する代わりに、実行を継続し、失敗をテストの失敗として記録します。テスト中に発生したすべてのエラーは、テストが完了するまで表示されます。
import { expect, test } from 'vitest';
test('expect.soft test', () => {
expect.soft(1 + 1).toBe(3); // テストを失敗として記録し、処理を継続します
expect.soft(1 + 2).toBe(4); // テストを失敗として記録し、処理を継続します
});
// テストの最後に、上記のエラーが表示されます。
expect
と組み合わせて使用することも可能です。expect
のアサーションが失敗した場合、テストは終了し、全てのエラーが表示されます。
import { expect, test } from 'vitest';
test('expect.soft test', () => {
expect.soft(1 + 1).toBe(3); // テストを失敗として記録し、処理を継続します
expect(1 + 2).toBe(3); // 失敗してテストを終了し、以前のエラーがすべて出力されます
expect.soft(1 + 2).toBe(4); // 実行されません
});
WARNING
expect.soft
は、test
関数内でのみ使用できます。
not
not
を使用すると、アサーションの結果が反転します。例えば、以下のコードは input
の値が 2
と等しくないことを検証します。等しい場合、アサーションはエラーをスローし、テストが失敗します。
import { expect, test } from 'vitest';
const input = Math.sqrt(16);
expect(input).not.to.equal(2); // chai API
expect(input).not.toBe(2); // jest API
toBe
型:
(value: any) => Awaitable<void>
toBe
は、プリミティブが厳密に等しいか、オブジェクトが同じ参照を共有しているかを検証するために使用できます。これはexpect(Object.is(3, 3)).toBe(true)
を呼び出すのと同じです。オブジェクトが同じではないものの、その構造が同一であるかどうかを確認したい場合は、toEqual
を使用してください。例えば、以下のコードは、トレーダーが 13 個のリンゴを所有しているかどうかを確認します。
tsimport { expect, test } from 'vitest'; const stock = { type: 'apples', count: 13, }; test('stock has 13 apples', () => { // 在庫に13個のリンゴがあるか確認 expect(stock.type).toBe('apples'); expect(stock.count).toBe(13); }); test('stocks are the same', () => { // 在庫が同じか確認 const refStock = stock; // same reference(同じ参照) expect(stock).toBe(refStock); });
浮動小数点数で
toBe
を使用しないようにしてください。JavaScript はそれらを丸めるため、0.1 + 0.2
は厳密には0.3
ではありません。浮動小数点数を確実に検証するには、toBeCloseTo
アサーションを使用してください。
toBeCloseTo
型:
(value: number, numDigits?: number) => Awaitable<void>
toBeCloseTo
を使用して、浮動小数点数を比較します。オプションのnumDigits
引数は、小数点 以下 をチェックする桁数を制限します。例えば:tsimport { expect, test } from 'vitest'; test.fails('decimals are not equal in javascript', () => { // JavaScriptでは小数は厳密に等しくありません expect(0.2 + 0.1).toBe(0.3); // 0.2 + 0.1 is 0.30000000000000004 }); test('decimals are rounded to 5 after the point', () => { // 小数点以下5桁に丸められます // 0.2 + 0.1 is 0.30000 | "000000000004" removed expect(0.2 + 0.1).toBeCloseTo(0.3, 5); // nothing from 0.30000000000000004 is removed expect(0.2 + 0.1).not.toBeCloseTo(0.3, 50); });
toBeDefined
型:
() => Awaitable<void>
toBeDefined
は、値がundefined
と等しくないことを検証します。関数の 戻り値 が何らかの値を持つかどうかを確認する場合に便利です。tsimport { expect, test } from 'vitest'; function getApples() { return 3; } test('function returned something', () => { // 関数が何かを返したか確認 expect(getApples()).toBeDefined(); });
toBeUndefined
型:
() => Awaitable<void>
toBeDefined
の反対で、toBeUndefined
は、値がundefined
と等しい ことを検証します。関数が何も 返していない かどうかを確認する場合に便利です。tsimport { expect, test } from 'vitest'; function getApplesFromStock(stock) { if (stock === 'Bill') return 13; } test("mary doesn't have a stock", () => { // Maryは在庫を持っていません(Maryは在庫を持っていないか確認) expect(getApplesFromStock('Mary')).toBeUndefined(); });
toBeTruthy
型:
() => Awaitable<void>
toBeTruthy
は、値がブール値に変換されたときにtrue
であることを検証します。値の具体的な内容を気にせず、true
に変換できるかどうかを知りたい場合に便利です。例えば、このコードでは、
stocks.getInfo
の戻り値を気にしません。それは複雑なオブジェクト、文字列、またはその他の何かかもしれません。コードはそれでも動作します。tsimport { Stocks } from './stocks.js'; const stocks = new Stocks(); stocks.sync('Bill'); if (stocks.getInfo('Bill')) stocks.sell('apples', 'Bill');
したがって、
stocks.getInfo
が truthy であることをテストしたい場合は、次のように記述できます。tsimport { expect, test } from 'vitest'; import { Stocks } from './stocks.js'; const stocks = new Stocks(); test('if we know Bill stock, sell apples to him', () => { // Billの在庫を知っている場合は、彼にリンゴを売る stocks.sync('Bill'); expect(stocks.getInfo('Bill')).toBeTruthy(); });
JavaScript のすべての値は truthy です。ただし、
false
、0
、''
、null
、undefined
、およびNaN
は除きます。
toBeFalsy
型:
() => Awaitable<void>
toBeFalsy
は、値がブール値に変換されたときにfalse
であることを検証します。値の具体的な内容を気にせず、false
に変換できるかどうかを知りたい場合に便利です。例えば、このコードでは、
stocks.stockFailed
の戻り値を気にしません。それは任意の falsy 値を返すかもしれませんが、コードはそれでも動作します。tsimport { Stocks } from './stocks.js'; const stocks = new Stocks(); stocks.sync('Bill'); if (!stocks.stockFailed('Bill')) stocks.sell('apples', 'Bill');
したがって、
stocks.stockFailed
が falsy であることをテストしたい場合は、次のように記述できます。tsimport { expect, test } from 'vitest'; import { Stocks } from './stocks.js'; const stocks = new Stocks(); test("if Bill stock hasn't failed, sell apples to him", () => { // Billの在庫が失敗していない場合は、彼にリンゴを売る stocks.syncStocks('Bill'); expect(stocks.stockFailed('Bill')).toBeFalsy(); });
JavaScript のすべての値は truthy です。ただし、
false
、0
、''
、null
、undefined
、およびNaN
は除きます。
toBeNull
型:
() => Awaitable<void>
toBeNull
は、値がnull
であるかどうかを検証します。.toBe(null)
のエイリアスです。tsimport { expect, test } from 'vitest'; function apples() { return null; } test("we don't have apples", () => { // リンゴがないか確認 expect(apples()).toBeNull(); });
toBeNaN
型:
() => Awaitable<void>
toBeNaN
は、値がNaN
であるかどうかを検証します。.toBe(NaN)
のエイリアスです。tsimport { expect, test } from 'vitest'; let i = 0; function getApplesCount() { i++; return i > 1 ? Number.NaN : i; } test('getApplesCount has some unusual side effects...', () => { // getApplesCountにはいくつかの副作用があります... expect(getApplesCount()).not.toBeNaN(); expect(getApplesCount()).toBeNaN(); });
toBeTypeOf
型:
(c: 'bigint' | 'boolean' | 'function' | 'number' | 'object' | 'string' | 'symbol' | 'undefined') => Awaitable<void>
toBeTypeOf
は、実際の値が指定された型の型であるかどうかを検証します。tsimport { expect, test } from 'vitest'; const actual = 'stock'; test('stock is type of string', () => { // stockはstring型である expect(actual).toBeTypeOf('string'); });
toBeInstanceOf
型:
(c: any) => Awaitable<void>
toBeInstanceOf
は、実際の値が指定されたクラスのインスタンスであるかどうかを検証します。tsimport { expect, test } from 'vitest'; import { Stocks } from './stocks.js'; const stocks = new Stocks(); test('stocks are instance of Stocks', () => { // stocksはStocksのインスタンスである expect(stocks).toBeInstanceOf(Stocks); });
toBeGreaterThan
型:
(n: number | bigint) => Awaitable<void>
toBeGreaterThan
は、実際の値が指定された値より大きいかどうかを検証します。等しい値はテストに失敗します。tsimport { expect, test } from 'vitest'; import { getApples } from './stocks.js'; test('have more then 10 apples', () => { // 10個以上のリンゴがあるか expect(getApples()).toBeGreaterThan(10); });
toBeGreaterThanOrEqual
型:
(n: number | bigint) => Awaitable<void>
toBeGreaterThanOrEqual
は、実際の値が指定された値以上であるかどうかを検証します。tsimport { expect, test } from 'vitest'; import { getApples } from './stocks.js'; test('have 11 apples or more', () => { // 11個以上のリンゴがあるか expect(getApples()).toBeGreaterThanOrEqual(11); });
toBeLessThan
型:
(n: number | bigint) => Awaitable<void>
toBeLessThan
は、実際の値が指定された値より小さいかどうかを検証します。等しい値はテストに失敗します。tsimport { expect, test } from 'vitest'; import { getApples } from './stocks.js'; test('have less then 20 apples', () => { // 20個未満のリンゴがあるか expect(getApples()).toBeLessThan(20); });
toBeLessThanOrEqual
型:
(n: number | bigint) => Awaitable<void>
toBeLessThanOrEqual
は、実際の値が指定された値以下であるかどうかを検証します。tsimport { expect, test } from 'vitest'; import { getApples } from './stocks.js'; test('have 11 apples or less', () => { // 11個以下のリンゴがあるか expect(getApples()).toBeLessThanOrEqual(11); });
toEqual
型:
(received: any) => Awaitable<void>
toEqual
は、実際の値が指定された値と等しいか、オブジェクトである場合は同じ構造を持っているかどうかを検証します(再帰的に比較します)。toEqual
とtoBe
の違いは、次の例で確認できます。tsimport { expect, test } from 'vitest'; const stockBill = { type: 'apples', count: 13, }; const stockMary = { type: 'apples', count: 13, }; test('stocks have the same properties', () => { // stocksは同じプロパティを持つ expect(stockBill).toEqual(stockMary); }); test('stocks are not the same', () => { // stocksは同じではない expect(stockBill).not.toBe(stockMary); });
WARNING
Error
オブジェクトに対して 深層的な等価性 は実行されません。何かがスローされたかどうかをテストするには、toThrowError
アサーションを使用してください。
toStrictEqual
型:
(received: any) => Awaitable<void>
toStrictEqual
は、実際の値が指定された値と等しいか、オブジェクトである場合は同じ構造を持っているかどうか(再帰的に比較します)、および同じ型であるかどうかを検証します。.toEqual
との違い:undefined
プロパティを持つキーがチェックされます。例えば、.toStrictEqual
を使用すると、{a: undefined, b: 2}
は{b: 2}
と一致しません。- 配列の疎性がチェックされます。例えば、
.toStrictEqual
を使用すると、[, 1]
は[undefined, 1]
と一致しません。 - オブジェクトの型が等しいかどうかがチェックされます。例えば、フィールド
a
とb
を持つクラス インスタンスは、フィールドa
とb
を持つリテラル オブジェクトと等しくありません。
tsimport { expect, test } from 'vitest'; class Stock { constructor(type) { this.type = type; } } test('structurally the same, but semantically different', () => { // 構造的には同じだが、意味的には異なる expect(new Stock('apples')).toEqual({ type: 'apples' }); expect(new Stock('apples')).not.toStrictEqual({ type: 'apples' }); });
toContain
型:
(received: string) => Awaitable<void>
toContain
は、実際の値が配列内に存在するかどうかを検証します。toContain
は、文字列が別の文字列の部分文字列であるかどうかを確認することもできます。tsimport { expect, test } from 'vitest'; import { getAllFruits } from './stocks.js'; test('the fruit list contains orange', () => { // フルーツリストにオレンジが含まれるか expect(getAllFruits()).toContain('orange'); });
toContainEqual
型:
(received: any) => Awaitable<void>
toContainEqual
は、特定の構造と値を持つアイテムが配列に含まれているかどうかを検証します。 各要素に対してtoEqual
のように機能します。tsimport { expect, test } from 'vitest'; import { getFruitStock } from './stocks.js'; test('apple available', () => { // リンゴが利用可能か expect(getFruitStock()).toContainEqual({ fruit: 'apple', count: 5 }); });
toHaveLength
型:
(received: number) => Awaitable<void>
toHaveLength
は、オブジェクトに.length
プロパティがあり、それが指定された数値に設定されているかどうかを検証します。tsimport { expect, test } from 'vitest'; test('toHaveLength', () => { expect('abc').toHaveLength(3); expect([1, 2, 3]).toHaveLength(3); expect('').not.toHaveLength(3); // doesn't have .length of 3 expect({ length: 3 }).toHaveLength(3); });
toHaveProperty
Type:
(key: any, received?: any) => Awaitable<void>
toHaveProperty
は、オブジェクトが指定されたkey
のプロパティを持っているかどうかを検証します。オプションの
received
引数(deep equality とも呼ばれます)をtoEqual
マッチャーのように指定することで、プロパティの値が一致するかどうかを検証できます。tsimport { expect, test } from 'vitest'; const invoice = { isActive: true, 'P.O': '12345', customer: { first_name: 'John', last_name: 'Doe', location: 'China', }, total_amount: 5000, items: [ { type: 'apples', quantity: 10, }, { type: 'oranges', quantity: 5, }, ], }; test('John Doe Invoice', () => { expect(invoice).toHaveProperty('isActive'); // キーの存在をアサート expect(invoice).toHaveProperty('total_amount', 5000); // キーが存在し、値が等しいことをアサート expect(invoice).not.toHaveProperty('account'); // このキーが存在しないことをアサート // ドット記法を使用した深い参照 expect(invoice).toHaveProperty('customer.first_name'); expect(invoice).toHaveProperty('customer.last_name', 'Doe'); expect(invoice).not.toHaveProperty('customer.location', 'India'); // キーを含む配列を使用した深い参照 expect(invoice).toHaveProperty('items[0].type', 'apples'); expect(invoice).toHaveProperty('items.0.type', 'apples'); // ドット記法も使用可能 // キーパスを含む配列を使用した深い参照 expect(invoice).toHaveProperty(['items', 0, 'type'], 'apples'); expect(invoice).toHaveProperty(['items', '0', 'type'], 'apples'); // 文字列記法も使用可能 // キーが深い参照として解釈されないように、キーを配列で囲む expect(invoice).toHaveProperty(['P.O'], '12345'); });
toMatch
Type:
(received: string | regexp) => Awaitable<void>
toMatch
は、文字列が正規表現または文字列に一致するかどうかをアサートします。tsimport { expect, test } from 'vitest'; test('top fruits', () => { expect('top fruits include apple, orange and grape').toMatch(/apple/); expect('applefruits').toMatch('fruit'); // toMatch は文字列も受け付けます });
TIP
エラーメッセージの値が切り詰められすぎている場合は、設定ファイルで chaiConfig.truncateThreshold の値を大きくしてください。
toMatchObject
Type:
(received: object | array) => Awaitable<void>
toMatchObject
は、オブジェクトが別のオブジェクトのプロパティのサブセットと一致するかどうかをアサートします。オブジェクトの配列を渡すことも可能です。これは、受け取った配列に余分な要素が含まれることを許容する
arrayContaining
とは異なり、2 つの配列の要素数が一致するかどうかを検証する際に役立ちます。tsimport { expect, test } from 'vitest'; const johnInvoice = { isActive: true, customer: { first_name: 'John', last_name: 'Doe', location: 'China', }, total_amount: 5000, items: [ { type: 'apples', quantity: 10, }, { type: 'oranges', quantity: 5, }, ], }; const johnDetails = { customer: { first_name: 'John', last_name: 'Doe', location: 'China', }, }; test('invoice has john personal details', () => { expect(johnInvoice).toMatchObject(johnDetails); }); test('the number of elements must match exactly', () => { // オブジェクトの配列が一致することをアサート expect([{ foo: 'bar' }, { baz: 1 }]).toMatchObject([ { foo: 'bar' }, { baz: 1 }, ]); });
toThrowError
Type:
(received: any) => Awaitable<void>
Alias:
toThrow
toThrowError
は、関数が呼び出されたときにエラーをスローするかどうかをアサートします。特定のエラーがスローされることを検証するために、オプションの引数を指定できます。
- 正規表現: エラーメッセージがパターンに一致するかどうか
- 文字列: エラーメッセージにサブストリングが含まれているかどうか
TIP
テスト対象のコードを関数内でラップする必要があります。そうしないと、エラーがキャッチされず、テストは失敗します。
たとえば、
getFruitStock('pineapples')
がエラーをスローすることをテストする場合、次のように記述できます。tsimport { expect, test } from 'vitest'; function getFruitStock(type) { if (type === 'pineapples') throw new DiabetesError( 'Pineapples are not good for people with diabetes' ); // 他の処理 } test('throws on pineapples', () => { // エラーメッセージに "diabetes" が含まれていることをテストします。これらは同じ意味です。 expect(() => getFruitStock('pineapples')).toThrowError(/diabetes/); expect(() => getFruitStock('pineapples')).toThrowError('diabetes'); // 正確なエラーメッセージをテストします expect(() => getFruitStock('pineapples')).toThrowError( /^Pineapples are not good for people with diabetes$/ ); });
TIP
非同期関数をテストするには、rejects と組み合わせて使用してください。
jsfunction getAsyncFruitStock() { return Promise.reject(new Error('empty')); } test('throws on pineapples', async () => { await expect(() => getAsyncFruitStock()).rejects.toThrowError('empty'); });
toMatchSnapshot
Type:
<T>(shape?: Partial<T> | string, message?: string) => void
これにより、値が最新のスナップショットと一致することを確認します。
テスト名に追加されるオプションの
hint
文字列引数を指定できます。Vitest はスナップショット名の末尾に番号を付与しますが、短い説明的なヒントの方が、単一の it または test ブロック内の複数のスナップショットを区別するのに役立つ場合があります。Vitest は、対応する.snap
ファイル内のスナップショットを名前でソートします。TIP
スナップショットが一致せずテストが失敗した場合、その不一致が予期されたものであれば、
u
キーを押してスナップショットを一時的に更新できます。 または、-u
または--update
CLI オプションを渡して、Vitest が常にテストを更新するようにすることもできます。tsimport { expect, test } from 'vitest'; test('matches snapshot', () => { const data = { foo: new Set(['bar', 'snapshot']) }; expect(data).toMatchSnapshot(); });
オブジェクトの形状のみをテストしていて、100% の互換性が必要ない場合は、オブジェクトの形状を指定することもできます。
tsimport { expect, test } from 'vitest'; test('matches snapshot', () => { const data = { foo: new Set(['bar', 'snapshot']) }; expect(data).toMatchSnapshot({ foo: expect.any(Set) }); });
toMatchInlineSnapshot
Type:
<T>(shape?: Partial<T> | string, snapshot?: string, message?: string) => void
これにより、値が最新のインラインスナップショットと一致することを確認します。
Vitest は、
inlineSnapshot
文字列引数を、外部の.snap
ファイルではなく、テストファイル内のマッチャーに追加および更新します。tsimport { expect, test } from 'vitest'; test('matches inline snapshot', () => { const data = { foo: new Set(['bar', 'snapshot']) }; // Vitest はスナップショットの更新時に次のコンテンツを更新します expect(data).toMatchInlineSnapshot(` { "foo": Set { "bar", "snapshot", }, } `); });
オブジェクトの形状のみをテストしていて、100% の互換性が必要ない場合は、オブジェクトの形状を指定することもできます。
tsimport { expect, test } from 'vitest'; test('matches snapshot', () => { const data = { foo: new Set(['bar', 'snapshot']) }; expect(data).toMatchInlineSnapshot( { foo: expect.any(Set) }, ` { "foo": Any<Set>, } ` ); });
toMatchFileSnapshot
Type:
<T>(filepath: string, message?: string) => Promise<void>
Version: Vitest 0.30.0 以降
スナップショットを、明示的に指定されたファイルの内容と比較または更新します(
.snap
ファイルの代替)。tsimport { expect, it } from 'vitest'; it('render basic', async () => { const result = renderHTML(h('div', { class: 'foo' })); await expect(result).toMatchFileSnapshot('./test/basic.output.html'); });
ファイルシステムの操作は非同期であるため、
toMatchFileSnapshot()
でawait
を使用する必要があることに注意してください。
toThrowErrorMatchingSnapshot
Type:
(message?: string) => void
toMatchSnapshot
と同じですが、toThrowError
と同じ値を予期します。関数が
Error
をスローした場合、スナップショットはエラーメッセージとなり、それ以外の場合は関数がスローした値になります。
toThrowErrorMatchingInlineSnapshot
Type:
(snapshot?: string, message?: string) => void
toMatchInlineSnapshot
と同じですが、toThrowError
と同じ値を予期します。関数がエラーをスローする場合、スナップショットはエラーメッセージになります。 それ以外の場合、スナップショットは関数によってスローされた値になります。
toHaveBeenCalled
Type:
() => Awaitable<void>
このアサーションは、関数が呼び出されたかどうかをテストするのに役立ちます。
expect
にはスパイ関数を渡す必要があります。tsimport { expect, test, vi } from 'vitest'; const market = { buy(subject: string, amount: number) { // ... }, }; test('spy function', () => { const buySpy = vi.spyOn(market, 'buy'); expect(buySpy).not.toHaveBeenCalled(); market.buy('apples', 10); expect(buySpy).toHaveBeenCalled(); });
toHaveBeenCalledTimes
Type:
(amount: number) => Awaitable<void>
このアサーションは、関数が特定の回数呼び出されたかどうかを検証します。
expect
にはスパイ関数を渡す必要があります。tsimport { expect, test, vi } from 'vitest'; const market = { buy(subject: string, amount: number) { // ... }, }; test('spy function called two times', () => { const buySpy = vi.spyOn(market, 'buy'); market.buy('apples', 10); market.buy('apples', 20); expect(buySpy).toHaveBeenCalledTimes(2); });
toHaveBeenCalledWith
Type:
(...args: any[]) => Awaitable<void>
このアサーションは、関数が特定の引数で少なくとも 1 回呼び出されたかどうかを検証します。
expect
にはスパイ関数を渡す必要があります。tsimport { expect, test, vi } from 'vitest'; const market = { buy(subject: string, amount: number) { // ... }, }; test('spy function', () => { const buySpy = vi.spyOn(market, 'buy'); market.buy('apples', 10); market.buy('apples', 20); expect(buySpy).toHaveBeenCalledWith('apples', 10); expect(buySpy).toHaveBeenCalledWith('apples', 20); });
toHaveBeenLastCalledWith
Type:
(...args: any[]) => Awaitable<void>
このアサーションは、関数が最後の呼び出しで特定の引数で呼び出されたかどうかを検証します。
expect
にはスパイ関数を渡す必要があります。tsimport { expect, test, vi } from 'vitest'; const market = { buy(subject: string, amount: number) { // ... }, }; test('spy function', () => { const buySpy = vi.spyOn(market, 'buy'); market.buy('apples', 10); market.buy('apples', 20); expect(buySpy).not.toHaveBeenLastCalledWith('apples', 10); expect(buySpy).toHaveBeenLastCalledWith('apples', 20); });
toHaveBeenNthCalledWith
Type:
(time: number, ...args: any[]) => Awaitable<void>
このアサーションは、関数が特定の呼び出し回数で、特定の引数で呼び出されたかどうかを検証します。カウントは 1 から始まります。したがって、2 回目の呼び出しを検証するには、
.toHaveBeenNthCalledWith(2, ...)
と記述します。expect
にはスパイ関数を渡す必要があります。tsimport { expect, test, vi } from 'vitest'; const market = { buy(subject: string, amount: number) { // ... }, }; test('first call of spy function called with right params', () => { const buySpy = vi.spyOn(market, 'buy'); market.buy('apples', 10); market.buy('apples', 20); expect(buySpy).toHaveBeenNthCalledWith(1, 'apples', 10); });
toHaveReturned
Type:
() => Awaitable<void>
このアサーションは、関数が少なくとも 1 回正常に値を返したかどうか (エラーをスローしなかったかどうか) を検証します。
expect
にはスパイ関数を渡す必要があります。tsimport { expect, test, vi } from 'vitest'; function getApplesPrice(amount: number) { const PRICE = 10; return amount * PRICE; } test('spy function returned a value', () => { const getPriceSpy = vi.fn(getApplesPrice); const price = getPriceSpy(10); expect(price).toBe(100); expect(getPriceSpy).toHaveReturned(); });
toHaveReturnedTimes
Type:
(amount: number) => Awaitable<void>
このアサーションは、関数が指定された回数だけ正常に値を返したかどうか (エラーをスローしなかったかどうか) を検証します。
expect
にはスパイ関数を渡す必要があります。tsimport { expect, test, vi } from 'vitest'; test('spy function returns a value two times', () => { const sell = vi.fn((product: string) => ({ product })); sell('apples'); sell('bananas'); expect(sell).toHaveReturnedTimes(2); });
toHaveReturnedWith
- 型:
(returnValue: any) => Awaitable<void>
このアサーションは、関数が少なくとも一度、特定の値を正常に返したかどうかを検証します。expect
に渡されるのはスパイ関数である必要があります。
import { expect, test, vi } from 'vitest';
test('スパイ関数が商品を返す', () => {
const sell = vi.fn((product: string) => ({ product }));
sell('apples');
expect(sell).toHaveReturnedWith({ product: 'apples' });
});
toHaveLastReturnedWith
- 型:
(returnValue: any) => Awaitable<void>
このアサーションは、関数が最後に呼び出された際に、特定の値を正常に返したかどうかを検証します。expect
に渡されるのはスパイ関数である必要があります。
import { expect, test, vi } from 'vitest';
test('スパイ関数が最後の呼び出しで bananas を返す', () => {
const sell = vi.fn((product: string) => ({ product }));
sell('apples');
sell('bananas');
expect(sell).toHaveLastReturnedWith({ product: 'bananas' });
});
toHaveNthReturnedWith
- 型:
(time: number, returnValue: any) => Awaitable<void>
このアサーションは、関数が特定の呼び出し回数で、特定の値を正常に返したかどうかを検証します。expect
に渡されるのはスパイ関数である必要があります。
import { expect, test, vi } from 'vitest';
test('スパイ関数が2回目の呼び出しで bananas を返す', () => {
const sell = vi.fn((product: string) => ({ product }));
sell('apples');
sell('bananas');
expect(sell).toHaveNthReturnedWith(2, { product: 'bananas' });
});
toSatisfy
- 型:
(predicate: (value: any) => boolean) => Awaitable<void>
このアサーションは、値が特定の述語(条件)を満たしているかどうかを確認します。
describe('toSatisfy()', () => {
const isOdd = (value: number) => value % 2 !== 0;
it('1 の場合に成功する', () => {
expect(1).toSatisfy(isOdd);
});
it('否定形の場合に成功する', () => {
expect(2).not.toSatisfy(isOdd);
});
});
resolves
型:
Promisify<Assertions>
resolves
は、非同期コードの検証におけるボイラープレートコードを削減することを目的としています。これを使用すると、解決済みの Promise から値を取り出し、通常のアサーションでその値を検証できます。Promise が拒否された場合、テストは失敗します。これは同じ
Assertions
オブジェクトを返しますが、すべてのマッチャーがPromise
を返すため、await
が必要です。chai
アサーションでも動作します。たとえば、API 呼び出しを行い、何らかのデータを返す関数がある場合、次のコードを使用してその戻り値を検証できます。
tsimport { expect, test } from 'vitest'; async function buyApples() { return fetch('/buy/apples').then(r => r.json()); } test('buyApples が新しい stock id を返す', async () => { // toEqual は Promise を返すようになったため、必ず await する必要があります await expect(buyApples()).resolves.toEqual({ id: 1 }); // jest API await expect(buyApples()).resolves.to.equal({ id: 1 }); // chai API });
WARNING
アサーションを
await
しないと、毎回成功する誤検出が発生します。アサーションが実際に呼び出されるようにするには、expect.assertions(number)
を使用できます。
rejects
型:
Promisify<Assertions>
rejects
は、非同期コードの検証におけるボイラープレートコードを削減することを目的としています。これを使用すると、Promise が拒否された理由を取り出し、通常のアサーションでその値を検証できます。Promise が正常に解決された場合、テストは失敗します。これは同じ
Assertions
オブジェクトを返しますが、すべてのマッチャーがPromise
を返すため、await
が必要です。chai
アサーションでも動作します。たとえば、呼び出すと失敗する関数がある場合、次のコードを使用して拒否理由を検証できます。
tsimport { expect, test } from 'vitest'; async function buyApples(id) { if (!id) throw new Error('no id'); } test('buyApples は id が指定されていない場合にエラーをスローする', async () => { // toThrow は Promise を返すようになったため、必ず await する必要があります await expect(buyApples()).rejects.toThrow('no id'); });
WARNING
アサーションを
await
しないと、毎回成功する誤検出が発生します。アサーションが実際に呼び出されたことを確認するには、expect.assertions(number)
を使用できます。
expect.assertions
型:
(count: number) => void
テストの成功/失敗に関わらず、テスト中に特定のアサーションが呼び出された回数を検証します。非同期コードが呼び出されたかどうかを確認する場合に役立ちます。
たとえば、非同期的に 2 つのマッチャーを呼び出す関数がある場合、それらが実際に呼び出されたことを検証できます。
tsimport { expect, test } from 'vitest'; async function doAsync(...cbs) { await Promise.all(cbs.map((cb, index) => cb({ index }))); } test('すべてのアサーションが呼び出される', async () => { expect.assertions(2); function callback1(data) { expect(data).toBeTruthy(); } function callback2(data) { expect(data).toBeTruthy(); } await doAsync(callback1, callback2); });
WARNING
assertions
を非同期の並行テストで使用する場合は、正しいテストが検出されるように、ローカルの テストコンテキスト からのexpect
を使用する必要があります。
expect.hasAssertions
型:
() => void
テストの成功/失敗に関わらず、テスト中に少なくとも 1 つのアサーションが呼び出されたことを検証します。非同期コードが呼び出されたかどうかを確認する場合に役立ちます。
たとえば、コールバックを呼び出すコードがある場合、コールバック内でアサーションを作成できますが、アサーションが呼び出されたかどうかを確認しないと、テストは常に成功します。
tsimport { expect, test } from 'vitest'; import { db } from './db.js'; const cbs = []; function onSelect(cb) { cbs.push(cb); } // db から選択した後、すべてのコールバックを呼び出す function select(id) { return db.select({ id }).then(data => { return Promise.all(cbs.map(cb => cb(data))); }); } test('コールバックが呼び出された', async () => { expect.hasAssertions(); onSelect(data => { // select で呼び出す必要がある expect(data).toBeTruthy(); }); // await しないと、テストは失敗する // expect.hasAssertions() がないと、テストは成功する await select(3); });
expect.unreachable
型:
(message?: string) => never
このメソッドは、特定のコード行が実行されないことを検証するために使用されます。
たとえば、
build()
がsrc
フォルダがないディレクトリを受け取った場合に例外をスローすることをテストし、各エラーを個別に処理したい場合、次のようにすることができます。tsimport { expect, test } from 'vitest'; async function build(dir) { if (dir.includes('no-src')) throw new Error(`${dir}/src does not exist`); } const errorDirs = [ 'no-src-folder', // ... ]; test.each(errorDirs)('build が "%s" で失敗する', async dir => { try { await build(dir); expect.unreachable('ビルドが成功するはずがない'); } catch (err: any) { expect(err).toBeInstanceOf(Error); expect(err.stack).toContain('build'); switch (dir) { case 'no-src-folder': expect(err.message).toBe(`${dir}/src does not exist`); break; default: // すべてのエラーテストをカバーする expect.unreachable('すべてのエラーテストが処理されている必要がある'); break; } } });
expect.anything
型:
() => any
この非対称マッチャーは、等価性チェックで使用すると、常に
true
を返します。プロパティの存在のみを確認したい場合に役立ちます。tsimport { expect, test } from 'vitest'; test('オブジェクトに "apples" キーがある', () => { expect({ apples: 22 }).toEqual({ apples: expect.anything() }); });
expect.any
型:
(constructor: unknown) => any
この非対称マッチャーは、等価性チェックで使用すると、値が指定されたコンストラクターのインスタンスである場合にのみ
true
を返します。毎回生成される値があり、型が適切であることのみを確認したい場合に役立ちます。tsimport { expect, test } from 'vitest'; import { generateId } from './generators.js'; test('"id" が数値である', () => { expect({ id: generateId() }).toEqual({ id: expect.any(Number) }); });
expect.arrayContaining
型:
<T>(expected: T[]) => any
この非対称マッチャーは、等価性チェックで使用すると、値が配列であり、指定された項目が含まれている場合に
true
を返します。tsimport { expect, test } from 'vitest'; test("バスケットに 'Fuji' が含まれている", () => { const basket = { varieties: ['Empire', 'Fuji', 'Gala'], count: 3, }; expect(basket).toEqual({ count: 3, varieties: expect.arrayContaining(['Fuji']), }); });
TIP
このマッチャーで
expect.not
を使用して、期待値を否定できます。
expect.objectContaining
型:
(expected: any) => any
この非対称マッチャーは、等価性チェックで使用すると、値が同じ構造を持つ場合に
true
を返します。tsimport { expect, test } from 'vitest'; test("バスケットに 'Empire' という名前のリンゴがある", () => { const basket = { varieties: [ { name: 'Empire', count: 1, }, ], }; expect(basket).toEqual({ varieties: [expect.objectContaining({ name: 'Empire' })], }); });
TIP
このマッチャーで
expect.not
を使用して、期待値を否定できます。
expect.stringContaining
型:
(expected: any) => any
この非対称マッチャーは、等価性チェックで使用すると、値が文字列であり、指定された部分文字列が含まれている場合に
true
を返します。tsimport { expect, test } from 'vitest'; test("variety の名前が 'Emp' を含む", () => { const variety = { name: 'Empire', count: 1, }; expect(variety).toEqual({ name: expect.stringContaining('Emp'), count: 1, }); });
TIP
このマッチャーで
expect.not
を使用して、期待値を否定できます。
expect.stringMatching
型:
(expected: any) => any
この非対称マッチャーは、等価性チェックで使用すると、値が文字列であり、指定された部分文字列が含まれている場合、または文字列が正規表現に一致する場合に
true
を返します。tsimport { expect, test } from 'vitest'; test("variety の名前が 're' で終わる", () => { const variety = { name: 'Empire', count: 1, }; expect(variety).toEqual({ name: expect.stringMatching(/re$/), count: 1, }); });
TIP
このマッチャーで
expect.not
を使用して、期待値を否定できます。
expect.addSnapshotSerializer
型:
(plugin: PrettyFormatPlugin) => void
このメソッドは、スナップショットを作成するときに呼び出されるカスタムシリアライザーを追加します。これは高度な機能です。詳細については、カスタムシリアライザーに関するガイド を参照してください。
カスタムシリアライザーを追加する場合は、
setupFiles
内でこのメソッドを呼び出す必要があります。これはすべてのスナップショットに影響します。TIP
以前に Vue CLI を Jest で使用していた場合は、jest-serializer-vue をインストールすることをお勧めします。そうしないと、スナップショットが文字列で囲まれ、
"
がエスケープ処理されます。
expect.extend
型:
(matchers: MatchersObject) => void
デフォルトのマッチャーを独自のマッチャーで拡張することができます。この関数は、カスタムマッチャーでマッチャーオブジェクトを拡張するために使用されます。
そのようにマッチャーを定義すると、
expect.stringContaining
のように使用できる非対称マッチャーも作成されます。tsimport { expect, test } from 'vitest'; test('カスタムマッチャー', () => { expect.extend({ toBeFoo: (received, expected) => { if (received !== 'foo') { return { message: () => `expected '${received}' to be foo`, pass: false, }; } }, }); expect('foo').toBeFoo(); expect({ foo: 'foo' }).toEqual({ foo: expect.toBeFoo() }); });
TIP
すべてのテストでマッチャーを表示する場合は、
setupFiles
内でこのメソッドを呼び出す必要があります。この関数は Jest の
expect.extend
と互換性があるため、それを使用してカスタムマッチャーを作成するライブラリは Vitest で動作します。TypeScript を使用している場合、Vitest 0.31.0 以降では、次のコードを使用して、環境宣言ファイル (例:
vitest.d.ts
) でデフォルトのAssertion
インターフェイスを拡張できます。tsinterface CustomMatchers<R = unknown> { toBeFoo(): R; } declare module 'vitest' { interface Assertion<T = any> extends CustomMatchers<T> {} interface AsymmetricMatchersContaining extends CustomMatchers {} }
WARNING
tsconfig.json
に環境宣言ファイルを含めることを忘れないでください。TIP
詳細については、マッチャーの拡張に関するガイド を確認してください。