跳到內容

expect

下列類型用於下方的類型簽章

ts
type Awaitable<T> = T | PromiseLike<T>

expect 用於建立斷言。在此脈絡中,斷言 是可呼叫函式,用於斷言陳述。Vitest 預設提供 chai 斷言,以及建構於 chai 上的 Jest 相容斷言。

例如,此程式碼斷言 input 值等於 2。如果不是,斷言會擲回錯誤,測試就會失敗。

ts
import {  } from 'vitest'

const  = .(4)

()..(2) // chai API
().(2) // jest API

技術上,此範例並未使用 test 函式,因此在主控台中,您會看到 Node.js 錯誤,而非 Vitest 輸出。如需深入了解 test,請閱讀 測試 API 參考

此外,expect 可用於靜態存取後述的比對器函式,以及更多功能。

警告

如果表達式沒有類型錯誤,expect 對測試類型沒有影響。如果您想使用 Vitest 作為 類型檢查器,請使用 expectTypeOfassertType

soft

  • 類型: ExpectStatic & (actual: any) => Assertions

expect.soft 的功能類似於 expect,但它不會在斷言失敗時終止測試執行,而是繼續執行並將失敗標記為測試失敗。測試期間遇到的所有錯誤都會顯示,直到測試完成。

ts
import { ,  } from 'vitest'

('expect.soft test', () => {
  .(1 + 1).(3) // mark the test as fail and continue
  .(1 + 2).(4) // mark the test as fail and continue
})
// At the end of the test, the above errors will be output.

它也可以與 expect 一起使用。如果 expect 斷言失敗,測試將終止,所有錯誤都將顯示。

ts
import { ,  } from 'vitest'

('expect.soft test', () => {
  .(1 + 1).(3) // mark the test as fail and continue
  (1 + 2).(4) // failed and terminate the test, all previous errors will be output
  .(1 + 3).(5) // do not run
})

警告

expect.soft 只能在 test 函數內使用。

not

使用 not 會否定斷言。例如,此程式碼斷言 input 值不等於 2。如果相等,斷言會擲出錯誤,測試將失敗。

ts
import { ,  } from 'vitest'

const  = .(16)

()...(2) // chai API
()..(2) // jest API

toBe

  • 類型: (value: any) => Awaitable<void>

toBe 可用於斷言基本類型是否相等或物件是否共用相同的參考。它等於呼叫 expect(Object.is(3, 3)).toBe(true)。如果物件不同,但您想檢查它們的結構是否相同,可以使用 toEqual

例如,以下程式碼檢查交易員是否有 13 個蘋果。

ts
import { ,  } from 'vitest'

const  = {
  : 'apples',
  : 13,
}

('stock has 13 apples', () => {
  (.).('apples')
  (.).(13)
})

('stocks are the same', () => {
  const  =  // same reference

  ().()
})

請盡量不要對浮點數使用 toBe。由於 JavaScript 會將它們四捨五入,因此 0.1 + 0.2 嚴格來說不等於 0.3。若要可靠地斷言浮點數,請使用 toBeCloseTo 斷言。

toBeCloseTo

  • 類型: (value: number, numDigits?: number) => Awaitable<void>

使用 toBeCloseTo 比較浮點數。選用的 numDigits 參數限制小數點要檢查的位數。例如

ts
import { ,  } from 'vitest'

.('decimals are not equal in javascript', () => {
  (0.2 + 0.1).(0.3) // 0.2 + 0.1 is 0.30000000000000004
})

('decimals are rounded to 5 after the point', () => {
  // 0.2 + 0.1 is 0.30000 | "000000000004" removed
  (0.2 + 0.1).(0.3, 5)
  // nothing from 0.30000000000000004 is removed
  (0.2 + 0.1)..(0.3, 50)
})

toBeDefined

  • 類型: () => Awaitable<void>

toBeDefined 斷言值不等於 undefined。有用的使用案例是檢查函數是否回傳任何內容。

ts
import { ,  } from 'vitest'

function () {
  return 3
}

('function returned something', () => {
  (()).()
})

toBeUndefined

  • 類型: () => Awaitable<void>

toBeDefined 相反,toBeUndefined 斷言值等於 undefined。有用的使用案例是檢查函式是否尚未 傳回 任何內容。

ts
import { ,  } from 'vitest'

function (: string) {
  if ( === 'Bill')
    return 13
}

('mary doesn\'t have a stock', () => {
  (('Mary')).()
})

toBeTruthy

  • 類型: () => Awaitable<void>

toBeTruthy 斷言值在轉換為布林值時為真。如果您不關心值,但只想了解它是否可以轉換為 true,這會很有用。

例如,有這段程式碼,您不關心 stocks.getInfo 的傳回值 - 它可能是複雜的物件、字串或其他任何內容。程式碼仍然會執行。

ts
import { Stocks } from './stocks.js'

const stocks = new Stocks()
stocks.sync('Bill')
if (stocks.getInfo('Bill'))
  stocks.sell('apples', 'Bill')

因此,如果您想測試 stocks.getInfo 是否為真,您可以撰寫

ts
import { expect, test } from 'vitest'
import { Stocks } from './stocks.js'

const stocks = new Stocks()

test('if we know Bill stock, sell apples to him', () => {
  stocks.sync('Bill')
  expect(stocks.getInfo('Bill')).toBeTruthy()
})

JavaScript 中的所有內容都是真值,除了 falsenullundefinedNaN0-00n""document.all

toBeFalsy

  • 類型: () => Awaitable<void>

toBeFalsy 斷言值在轉換為布林值時為假。如果您不關心值,但只想了解它是否可以轉換為 false,這會很有用。

例如,有這段程式碼,您不關心 stocks.stockFailed 的傳回值 - 它可能會傳回任何假值,但程式碼仍然會執行。

ts
import { Stocks } from './stocks.js'

const stocks = new Stocks()
stocks.sync('Bill')
if (!stocks.stockFailed('Bill'))
  stocks.sell('apples', 'Bill')

因此,如果您想測試 stocks.stockFailed 是否為假,您可以撰寫

ts
import { expect, test } from 'vitest'
import { Stocks } from './stocks.js'

const stocks = new Stocks()

test('if Bill stock hasn\'t failed, sell apples to him', () => {
  stocks.syncStocks('Bill')
  expect(stocks.stockFailed('Bill')).toBeFalsy()
})

JavaScript 中的所有內容都是真值,除了 falsenullundefinedNaN0-00n""document.all

toBeNull

  • 類型: () => Awaitable<void>

toBeNull 僅斷言某個東西是否為 null.toBe(null) 的別名。

ts
import { ,  } from 'vitest'

function () {
  return null
}

('we don\'t have apples', () => {
  (()).()
})

toBeNaN

  • 類型: () => Awaitable<void>

toBeNaN 僅斷言某個東西是否為 NaN.toBe(NaN) 的別名。

ts
import { ,  } from 'vitest'

let  = 0

function () {
  ++
  return  > 1 ? . : 
}

('getApplesCount has some unusual side effects...', () => {
  (())..()
  (()).()
})

toBeTypeOf

  • 類型: (c: 'bigint' | 'boolean' | 'function' | 'number' | 'object' | 'string' | 'symbol' | 'undefined') => Awaitable<void>

toBeTypeOf 斷言實際值是否為接收類型類型。

ts
import { ,  } from 'vitest'

const  = 'stock'

('stock is type of string', () => {
  ().('string')
})

toBeInstanceOf

  • 類型: (c: any) => Awaitable<void>

toBeInstanceOf 斷言實際值是否為接收類別的實例。

ts
import { expect, test } from 'vitest'
import { Stocks } from './stocks.js'

const stocks = new Stocks()

test('stocks are instance of Stocks', () => {
  expect(stocks).toBeInstanceOf(Stocks)
})

toBeGreaterThan

  • 類型: (n: number | bigint) => Awaitable<void>

toBeGreaterThan 斷言實際值是否大於接收值。相等的值將會失敗測試。

ts
import { expect, test } from 'vitest'
import { getApples } from './stocks.js'

test('have more then 10 apples', () => {
  expect(getApples()).toBeGreaterThan(10)
})

toBeGreaterThanOrEqual

  • 類型: (n: number | bigint) => Awaitable<void>

toBeGreaterThanOrEqual 斷言實際值是否大於或等於接收值。

ts
import { expect, test } from 'vitest'
import { getApples } from './stocks.js'

test('have 11 apples or more', () => {
  expect(getApples()).toBeGreaterThanOrEqual(11)
})

toBeLessThan

  • 類型: (n: number | bigint) => Awaitable<void>

toBeLessThan 斷言實際值是否小於接收值。相等的值將會失敗測試。

ts
import { expect, test } from 'vitest'
import { getApples } from './stocks.js'

test('have less then 20 apples', () => {
  expect(getApples()).toBeLessThan(20)
})

toBeLessThanOrEqual

  • 類型: (n: number | bigint) => Awaitable<void>

toBeLessThanOrEqual 斷言實際值是否小於或等於接收值。

ts
import { expect, test } from 'vitest'
import { getApples } from './stocks.js'

test('have 11 apples or less', () => {
  expect(getApples()).toBeLessThanOrEqual(11)
})

toEqual

  • 類型: (received: any) => Awaitable<void>

toEqual 斷言實際值是否等於接收值或有相同的結構,如果它是一個物件(遞迴比較它們)。你可以在這個範例中看到 toEqualtoBe 的差異

ts
import { ,  } from 'vitest'

const  = {
  : 'apples',
  : 13,
}

const  = {
  : 'apples',
  : 13,
}

('stocks have the same properties', () => {
  ().()
})

('stocks are not the same', () => {
  ()..()
})

警告

對於 Error 物件,不會執行深度相等性。只會考慮 Errormessage 屬性來判斷相等性。若要自訂相等性來檢查 message 以外的屬性,請使用 expect.addEqualityTesters。若要測試是否拋出錯誤,請使用 toThrowError 斷言。

toStrictEqual

  • 類型: (received: any) => Awaitable<void>

toStrictEqual 斷言實際值是否等於接收值或有相同的結構(如果它是一個物件,則遞迴比較它們),且類型相同。

.toEqual 的差異

  • 會檢查具有 undefined 屬性的鍵。例如,使用 .toStrictEqual 時,{a: undefined, b: 2} 不會與 {b: 2} 相符。
  • 會檢查陣列的稀疏性。例如,使用 .toStrictEqual 時,[, 1] 不會與 [undefined, 1] 相符。
  • 會檢查物件類型是否相等。例如,具有欄位 ab 的類別實例不會等於具有欄位 ab 的文字物件。
ts
import { 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 也可以檢查字串是否為另一個字串的子字串。自 Vitest 1.0 以來,如果你在類似瀏覽器的環境中執行測試,此斷言也可以檢查類別是否包含在 classList 中,或一個元素是否在另一個元素中。

ts
import { expect, test } from 'vitest'
import { getAllFruits } from './stocks.js'

test('the fruit list contains orange', () => {
  expect(getAllFruits()).toContain('orange')

  const element = document.querySelector('#el')
  // element has a class
  expect(element.classList).toContain('flex')
  // element is inside another one
  expect(document.querySelector('#wrapper')).toContain(element)
})

toContainEqual

  • 類型: (received: any) => Awaitable<void>

toContainEqual 斷言陣列中是否包含具有特定結構和值的項目。它在每個元素內部像 toEqual 一樣運作。

ts
import { 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 屬性,且設定為特定數字值。

ts
import { ,  } from 'vitest'

('toHaveLength', () => {
  ('abc').(3)
  ([1, 2, 3]).(3)

  ('')..(3) // doesn't have .length of 3
  ({ : 3 }).(3)
})

toHaveProperty

  • 類型: (key: any, received?: any) => Awaitable<void>

toHaveProperty 斷言物件是否存在於提供的參考 key 中的屬性。

您也可以提供一個可選的值引數,也稱為深度相等性,就像 toEqual 比對器用於比對接收到的屬性值。

ts
import { ,  } from 'vitest'

const  = {
  'isActive': true,
  'P.O': '12345',
  'customer': {
    : 'John',
    : 'Doe',
    : 'China',
  },
  'total_amount': 5000,
  'items': [
    {
      : 'apples',
      : 10,
    },
    {
      : 'oranges',
      : 5,
    },
  ],
}

('John Doe Invoice', () => {
  ().('isActive') // assert that the key exists
  ().('total_amount', 5000) // assert that the key exists and the value is equal

  ()..('account') // assert that this key does not exist

  // Deep referencing using dot notation
  ().('customer.first_name')
  ().('customer.last_name', 'Doe')
  ()..('customer.location', 'India')

  // Deep referencing using an array containing the key
  ().('items[0].type', 'apples')
  ().('items.0.type', 'apples') // dot notation also works

  // Deep referencing using an array containing the keyPath
  ().(['items', 0, 'type'], 'apples')
  ().(['items', '0', 'type'], 'apples') // string notation also works

  // Wrap your key in an array to avoid the key from being parsed as a deep reference
  ().(['P.O'], '12345')
})

toMatch

  • 類型: (received: string | regexp) => Awaitable<void>

toMatch 斷言字串是否與正規表示式或字串相符。

ts
import { ,  } from 'vitest'

('top fruits', () => {
  ('top fruits include apple, orange and grape').(/apple/)
  ('applefruits').('fruit') // toMatch also accepts a string
})

toMatchObject

  • 類型: (received: object | array) => Awaitable<void>

toMatchObject 斷言物件是否與物件的子集屬性相符。

您也可以傳遞物件陣列。如果您想要檢查兩個陣列在元素數量上是否相符,這會很有用,與 arrayContaining 相反,它允許在接收到的陣列中額外增加元素。

ts
import { ,  } from 'vitest'

const  = {
  : true,
  : {
    : 'John',
    : 'Doe',
    : 'China',
  },
  : 5000,
  : [
    {
      : 'apples',
      : 10,
    },
    {
      : 'oranges',
      : 5,
    },
  ],
}

const  = {
  : {
    : 'John',
    : 'Doe',
    : 'China',
  },
}

('invoice has john personal details', () => {
  ().()
})

('the number of elements must match exactly', () => {
  // Assert that an array of object matches
  ([{ : 'bar' }, { : 1 }]).([
    { : 'bar' },
    { : 1 },
  ])
})

toThrowError

  • 類型: (received: any) => Awaitable<void>

  • 別名: toThrow

toThrowError 斷言當呼叫函式時,函式是否會擲回錯誤。

您可以提供一個可選的引數來測試是否擲回特定錯誤

  • 正規表示式:錯誤訊息與模式相符
  • 字串:錯誤訊息包含子字串

提示

您必須將程式碼包裝在函式中,否則錯誤不會被捕獲,測試將會失敗。

例如,如果我們想要測試 getFruitStock('pineapples') 是否會擲回錯誤,我們可以寫

ts
import { ,  } from 'vitest'

function (: string) {
  if ( === 'pineapples')
    throw new ('Pineapples are not in stock')

  // Do some other stuff
}

('throws on pineapples', () => {
  // Test that the error message says "stock" somewhere: these are equivalent
  (() => ('pineapples')).(/stock/)
  (() => ('pineapples')).('stock')

  // Test the exact error message
  (() => ('pineapples')).(
    /^Pineapples are not in stock$/,
  )
})

提示

若要測試非同步函式,請與 rejects 結合使用。

js
function () {
  return .(new ('empty'))
}

test('throws on pineapples', async () => {
  await expect(() => ()).rejects.toThrowError('empty')
})

toMatchSnapshot

  • 類型: <T>(shape?: Partial<T> | string, message?: string) => void

這可確保值與最近的快照相符。

您可以提供一個可選的 hint 字串引數,附加在測試名稱後方。儘管 Vitest 總會在快照名稱的結尾附加一個數字,但簡短的描述性提示可能比數字更有用,用於區分單一 it 或測試區塊中的多個快照。Vitest 會根據名稱在對應的 .snap 檔案中對快照進行排序。

提示

當快照不匹配並導致測試失敗時,如果預期發生不匹配,你可以按下 u 鍵一次更新快照。或者,你可以傳遞 -u--update CLI 選項,讓 Vitest 始終更新測試。

ts
import { ,  } from 'vitest'

('matches snapshot', () => {
  const  = { : new (['bar', 'snapshot']) }
  ().()
})

你也可以提供一個物件的形狀,如果你只是在測試一個物件的形狀,而不需要它 100% 相容

ts
import { ,  } from 'vitest'

('matches snapshot', () => {
  const  = { : new (['bar', 'snapshot']) }
  ().({ : .() })
})

toMatchInlineSnapshot

  • 類型: <T>(shape?: Partial<T> | string, snapshot?: string, message?: string) => void

這可確保值與最近的快照相符。

Vitest 將 inlineSnapshot 字串引數新增並更新至測試檔案中的比對器(而不是外部的 .snap 檔案)。

ts
import { ,  } from 'vitest'

('matches inline snapshot', () => {
  const  = { : new (['bar', 'snapshot']) }
  // Vitest will update following content when updating the snapshot
  ().(`
    {
      "foo": Set {
        "bar",
        "snapshot",
      },
    }
  `)
})

你也可以提供一個物件的形狀,如果你只是在測試一個物件的形狀,而不需要它 100% 相容

ts
import { ,  } from 'vitest'

('matches snapshot', () => {
  const  = { : new (['bar', 'snapshot']) }
  ().(
    { : .() },
    `
    {
      "foo": Any<Set>,
    }
  `
  )
})

toMatchFileSnapshot 0.30.0+

  • 類型: <T>(filepath: string, message?: string) => Promise<void>

將快照與明確指定檔案的內容進行比較或更新(而不是 .snap 檔案)。

ts
import { 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

  • 類型: (message?: string) => void

toMatchSnapshot 相同,但預期值與 toThrowError 相同。

toThrowErrorMatchingInlineSnapshot

  • 類型: (snapshot?: string, message?: string) => void

toMatchInlineSnapshot 相同,但預期值與 toThrowError 相同。

toHaveBeenCalled

  • 類型: () => Awaitable<void>

此斷言對於測試函式是否已呼叫很有用。需要將 spy 函式傳遞給 expect

ts
import { , ,  } from 'vitest'

const  = {
  (: string, : number) {
    // ...
  },
}

('spy function', () => {
  const  = .(, 'buy')

  ()..()

  .('apples', 10)

  ().()
})

toHaveBeenCalledTimes

  • 類型: (amount: number) => Awaitable<void>

此斷言檢查函式是否被呼叫特定次數。需要將 spy 函式傳遞給 expect

ts
import { , ,  } from 'vitest'

const  = {
  (: string, : number) {
    // ...
  },
}

('spy function called two times', () => {
  const  = .(, 'buy')

  .('apples', 10)
  .('apples', 20)

  ().(2)
})

toHaveBeenCalledWith

  • 類型: (...args: any[]) => Awaitable<void>

此斷言檢查函式是否至少被呼叫一次且帶有特定參數。需要將 spy 函式傳遞給 expect

ts
import { , ,  } from 'vitest'

const  = {
  (: string, : number) {
    // ...
  },
}

('spy function', () => {
  const  = .(, 'buy')

  .('apples', 10)
  .('apples', 20)

  ().('apples', 10)
  ().('apples', 20)
})

toHaveBeenLastCalledWith

  • 類型: (...args: any[]) => Awaitable<void>

此斷言檢查函式是否在其最後一次呼叫中帶有特定參數。需要將 spy 函式傳遞給 expect

ts
import { , ,  } from 'vitest'

const  = {
  (: string, : number) {
    // ...
  },
}

('spy function', () => {
  const  = .(, 'buy')

  .('apples', 10)
  .('apples', 20)

  ()..('apples', 10)
  ().('apples', 20)
})

toHaveBeenNthCalledWith

  • 類型: (time: number, ...args: any[]) => Awaitable<void>

此斷言檢查函式是否在特定時間帶有特定參數被呼叫。計數從 1 開始。因此,若要檢查第二個項目,您需要撰寫 .toHaveBeenNthCalledWith(2, ...)

需要將 spy 函式傳遞給 expect

ts
import { , ,  } from 'vitest'

const  = {
  (: string, : number) {
    // ...
  },
}

('first call of spy function called with right params', () => {
  const  = .(, 'buy')

  .('apples', 10)
  .('apples', 20)

  ().(1, 'apples', 10)
})

toHaveReturned

  • 類型: () => Awaitable<void>

此斷言檢查函式是否至少成功回傳一次值(即未擲回錯誤)。需要將 spy 函式傳遞給 expect

ts
import { , ,  } from 'vitest'

function (: number) {
  const  = 10
  return  * 
}

('spy function returned a value', () => {
  const  = .()

  const  = (10)

  ().(100)
  ().()
})

toHaveReturnedTimes

  • 類型: (amount: number) => Awaitable<void>

此斷言檢查函式是否成功回傳特定次數的值(即未擲回錯誤)。需要將 spy 函式傳遞給 expect

ts
import { , ,  } from 'vitest'

('spy function returns a value two times', () => {
  const  = .((: string) => ({  }))

  ('apples')
  ('bananas')

  ().(2)
})

toHaveReturnedWith

  • 類型: (returnValue: any) => Awaitable<void>

您可以呼叫此斷言以檢查函式是否至少成功回傳帶有特定參數的值。需要將 spy 函式傳遞給 expect

ts
import { , ,  } from 'vitest'

('spy function returns a product', () => {
  const  = .((: string) => ({  }))

  ('apples')

  ().({ : 'apples' })
})

toHaveLastReturnedWith

  • 類型: (returnValue: any) => Awaitable<void>

您可以呼叫此斷言以檢查函式是否在其最後一次呼叫中成功回傳帶有特定參數的值。需要將 spy 函式傳遞給 expect

ts
import { , ,  } from 'vitest'

('spy function returns bananas on a last call', () => {
  const  = .((: string) => ({  }))

  ('apples')
  ('bananas')

  ().({ : 'bananas' })
})

toHaveNthReturnedWith

  • 類型(time: number, returnValue: any) => Awaitable<void>

你可以呼叫此斷言,以檢查函式是否已在特定呼叫中成功傳回具有特定參數的值。需要將間諜函式傳遞給 expect

ts
import { , ,  } from 'vitest'

('spy function returns bananas on second call', () => {
  const  = .((: string) => ({  }))

  ('apples')
  ('bananas')

  ().(2, { : 'bananas' })
})

toSatisfy

  • 類型:(predicate: (value: any) => boolean) => Awaitable<void>

此斷言檢查值是否滿足特定謂詞。

ts
import { , ,  } from 'vitest'
('toSatisfy()', () => {
  const  = (: number) =>  % 2 !== 0

  ('pass with 0', () => {
    (1).()
  })

  ('pass with negation', () => {
    (2)..()
  })
})

resolves

  • 類型:Promisify<Assertions>

resolves 的目的是在斷言非同步程式碼時移除樣板。使用它來從待處理承諾中解開值,並使用一般斷言斷言其值。如果承諾遭到拒絕,則斷言將失敗。

它會傳回相同的 Assertions 物件,但現在所有比對器都會傳回 Promise,因此你需要 await 它。也可以搭配 chai 斷言使用。

例如,如果你有一個執行 API 呼叫並傳回一些資料的函式,你可以使用此程式碼來斷言其傳回值

ts
import { expect, test } from 'vitest'

async function buyApples() {
  return fetch('/buy/apples').then(r => r.json())
}

test('buyApples returns new stock id', async () => {
  // toEqual returns a promise now, so you HAVE to await it
  await expect(buyApples()).resolves.toEqual({ id: 1 }) // jest API
  await expect(buyApples()).resolves.to.equal({ id: 1 }) // chai API
})

警告

如果沒有等待斷言,則你會有一個每次都會通過的假陽性測試。若要確保實際呼叫斷言,你可以使用 expect.assertions(number)

rejects

  • 類型:Promisify<Assertions>

rejects 的目的是在斷言非同步程式碼時移除樣板。使用它來解開承諾遭到拒絕的原因,並使用一般斷言斷言其值。如果承諾成功解析,則斷言將失敗。

它會傳回相同的 Assertions 物件,但現在所有比對器都會傳回 Promise,因此你需要 await 它。也可以搭配 chai 斷言使用。

例如,如果你有一個在你呼叫時會失敗的函式,你可以使用此程式碼來斷言原因

ts
import { expect, test } from 'vitest'

async function buyApples(id) {
  if (!id)
    throw new Error('no id')
}

test('buyApples throws an error when no id provided', async () => {
  // toThrow returns a promise now, so you HAVE to await it
  await expect(buyApples()).rejects.toThrow('no id')
})

警告

如果沒有等待斷言,則你會有一個每次都會通過的假陽性測試。若要確保實際呼叫斷言,你可以使用 expect.assertions(number)

expect.assertions

  • 類型:(count: number) => void

在測試通過或失敗後,驗證測試期間是否呼叫了特定數量的斷言。一個有用的情況是檢查是否呼叫了非同步程式碼。

例如,如果我們有一個非同步呼叫兩個比對器的函式,我們可以斷言它們實際上已被呼叫。

ts
import { expect, test } from 'vitest'

async function doAsync(...cbs) {
  await Promise.all(
    cbs.map((cb, index) => cb({ index })),
  )
}

test('all assertions are called', async () => {
  expect.assertions(2)
  function callback1(data) {
    expect(data).toBeTruthy()
  }
  function callback2(data) {
    expect(data).toBeTruthy()
  }

  await doAsync(callback1, callback2)
})

警告

在將 assertions 與非同步並行測試搭配使用時,必須使用來自本機 測試內容expect,以確保偵測到正確的測試。

expect.hasAssertions

  • 類型: () => void

在測試通過或失敗後,驗證在測試期間至少呼叫過一個斷言。一個有用的情況是檢查非同步程式碼是否被呼叫。

例如,如果你有一個呼叫回呼函式的程式碼,我們可以在回呼函式內進行斷言,但如果我們不檢查是否呼叫了斷言,測試將始終通過。

ts
import { expect, test } from 'vitest'
import { db } from './db.js'

const cbs = []

function onSelect(cb) {
  cbs.push(cb)
}

// after selecting from db, we call all callbacks
function select(id) {
  return db.select({ id }).then((data) => {
    return Promise.all(
      cbs.map(cb => cb(data)),
    )
  })
}

test('callback was called', async () => {
  expect.hasAssertions()
  onSelect((data) => {
    // should be called on select
    expect(data).toBeTruthy()
  })
  // if not awaited, test will fail
  // if you don't have expect.hasAssertions(), test will pass
  await select(3)
})

expect.unreachable

  • 類型: (message?: string) => never

此方法用於斷言不應到達某一行。

例如,如果我們要測試 build() 會因為接收的目錄沒有 src 資料夾而擲回例外,並分別處理每個錯誤,我們可以這樣做

ts
import { 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 fails with "%s"', async (dir) => {
  try {
    await build(dir)
    expect.unreachable('Should not pass build')
  }
  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:
        // to exhaust all error tests
        expect.unreachable('All error test must be handled')
        break
    }
  }
})

expect.anything

  • 類型: () => any

此非對稱比對器在與等號檢查一起使用時,將始終傳回 true。如果你只是想確定屬性存在,這會很有用。

ts
import { expect, test } from 'vitest'

test('object has "apples" key', () => {
  expect({ apples: 22 }).toEqual({ apples: expect.anything() })
})

expect.any

  • 類型: (constructor: unknown) => any

此非對稱比對器在與等號檢查一起使用時,僅當值是指定建構函式的執行個體時,才會傳回 true。如果你有一個每次都會產生的值,而且你只想確定它存在於適當的類型中,這會很有用。

ts
import { expect, test } from 'vitest'
import { generateId } from './generators.js'

test('"id" is a number', () => {
  expect({ id: generateId() }).toEqual({ id: expect.any(Number) })
})

expect.closeTo 1.0.0+

  • 類型: (expected: any, precision?: number) => any

expect.closeTo 在比較物件屬性或陣列項目中的浮點數時很有用。如果你需要比較一個數字,請改用 .toBeCloseTo

可選的 numDigits 參數限制小數點 要檢查的數字位數。對於預設值 2,測試準則為 Math.abs(expected - received) < 0.005 (也就是 10 ** -2 / 2)

例如,此測試以 5 位數字的精度通過

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

  • 類型: <T>(expected: T[]) => any

當與等號檢查一起使用時,如果值為陣列且包含指定的項目,此非對稱比對器將傳回 true

ts
import { ,  } from 'vitest'

('basket includes fuji', () => {
  const  = {
    : [
      'Empire',
      'Fuji',
      'Gala',
    ],
    : 3
  }
  ().({
    : 3,
    : .(['Fuji'])
  })
})

提示

您可以將 expect.not 與此比對器一起使用,以否定預期的值。

expect.objectContaining

  • 類型: (expected: any) => any

當與等號檢查一起使用時,如果值具有相似的形狀,此非對稱比對器將傳回 true

ts
import { ,  } from 'vitest'

('basket has empire apples', () => {
  const  = {
    : [
      {
        : 'Empire',
        : 1,
      }
    ],
  }
  ().({
    : [
      .({ : 'Empire' }),
    ]
  })
})

提示

您可以將 expect.not 與此比對器一起使用,以否定預期的值。

expect.stringContaining

  • 類型: (expected: any) => any

當與等號檢查一起使用時,如果值為字串且包含指定的子字串,此非對稱比對器將傳回 true

ts
import { ,  } from 'vitest'

('variety has "Emp" in its name', () => {
  const  = {
    : 'Empire',
    : 1,
  }
  ().({
    : .('Emp'),
    : 1,
  })
})

提示

您可以將 expect.not 與此比對器一起使用,以否定預期的值。

expect.stringMatching

  • 類型: (expected: any) => any

當與等號檢查一起使用時,如果值為字串且包含指定的子字串,或如果字串符合正規表示式,此非對稱比對器將傳回 true

ts
import { ,  } from 'vitest'

('variety ends with "re"', () => {
  const  = {
    : 'Empire',
    : 1,
  }
  ().({
    : .(/re$/),
    : 1,
  })
})

提示

您可以將 expect.not 與此比對器一起使用,以否定預期的值。

expect.addSnapshotSerializer

  • 類型: (plugin: PrettyFormatPlugin) => void

此方法新增在建立快照時呼叫的客製化序列化器。這是一個進階功能 - 如果您想了解更多,請閱讀 客製化序列化器指南

如果您正在新增客製化序列化器,您應該在 setupFiles 內呼叫此方法。這將影響每個快照。

提示

如果您之前在 Jest 中使用 Vue CLI,您可能想要安裝 jest-serializer-vue。否則,您的快照將被包覆在字串中,這會導致 " 被跳脫。

expect.extend

  • 類型: (matchers: MatchersObject) => void

您可以用自己的預設比對器來延伸。此函式用於使用客製化比對器來延伸比對器物件。

當您以這種方式定義比對器時,您也會建立非對稱比對器,可以使用像 expect.stringContaining 這樣的比對器。

ts
import { expect, test } from 'vitest'

test('custom matchers', () => {
  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() })
})

提示

如果您希望您的比對器出現在每個測試中,您應該在 setupFiles 內呼叫此方法。

此函式與 Jest 的 expect.extend 相容,因此任何使用它來建立客製化比對器的程式庫都可以在 Vitest 中使用。

如果您正在使用 TypeScript,自 Vitest 0.31.0 起,您可以在環境宣告檔 (例如:vitest.d.ts) 中使用以下程式碼延伸預設的 Assertion 介面

ts
interface CustomMatchers<R = unknown> {
  toBeFoo: () => R
}

declare module 'vitest' {
  interface Assertion<T = any> extends CustomMatchers<T> {}
  interface AsymmetricMatchersContaining extends CustomMatchers {}
}

警告

別忘了在您的 tsconfig.json 中包含環境宣告檔。

提示

如果您想了解更多資訊,請查看延伸比對器的指南

expect.addEqualityTesters 1.2.0+

  • 類型: (tester: Array<Tester>) => void

您可以使用此方法來定義自訂測試器,這些方法由比對器使用,以測試兩個物件是否相等。它與 Jest 的 expect.addEqualityTesters 相容。

ts
import { ,  } from 'vitest'

class  {
  public : string

  constructor(: string) {
    this. = 
  }

  (: ): boolean {
    const  = this..(/ /g, '').()
    const  = ..(/ /g, '').()

    const  = .('').().('')
    const  = .('').().('')

    return  === 
  }
}

function (: unknown):  is  {
  return  instanceof 
}

function (: unknown, : unknown): boolean | undefined {
  const  = ()
  const  = ()

  if ( && )
    return .()

  else if ( === )
    return 

  else
    return false
}

.([])

('custom equality tester', () => {
  (new ('listen')).(new ('silent'))
})