Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Vitest 3.x reference skill covering configuration, test/describe APIs, mocking, coverage, snapshots, and concurrency.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/core-expect.md
1---2name: expect-api3description: Assertions with matchers, asymmetric matchers, and custom matchers4---56# Expect API78Vitest uses Chai assertions with Jest-compatible API.910## Basic Assertions1112```ts13import { expect, test } from 'vitest'1415test('assertions', () => {16// Equality17expect(1 + 1).toBe(2) // Strict equality (===)18expect({ a: 1 }).toEqual({ a: 1 }) // Deep equality1920// Truthiness21expect(true).toBeTruthy()22expect(false).toBeFalsy()23expect(null).toBeNull()24expect(undefined).toBeUndefined()25expect('value').toBeDefined()2627// Numbers28expect(10).toBeGreaterThan(5)29expect(10).toBeGreaterThanOrEqual(10)30expect(5).toBeLessThan(10)31expect(0.1 + 0.2).toBeCloseTo(0.3, 5)3233// Strings34expect('hello world').toMatch(/world/)35expect('hello').toContain('ell')3637// Arrays38expect([1, 2, 3]).toContain(2)39expect([{ a: 1 }]).toContainEqual({ a: 1 })40expect([1, 2, 3]).toHaveLength(3)4142// Objects43expect({ a: 1, b: 2 }).toHaveProperty('a')44expect({ a: 1, b: 2 }).toHaveProperty('a', 1)45expect({ a: { b: 1 } }).toHaveProperty('a.b', 1)46expect({ a: 1 }).toMatchObject({ a: 1 })4748// Types49expect('string').toBeTypeOf('string')50expect(new Date()).toBeInstanceOf(Date)51})52```5354## Negation5556```ts57expect(1).not.toBe(2)58expect({ a: 1 }).not.toEqual({ a: 2 })59```6061## Error Assertions6263```ts64// Sync errors - wrap in function65expect(() => throwError()).toThrow()66expect(() => throwError()).toThrow('message')67expect(() => throwError()).toThrow(/pattern/)68expect(() => throwError()).toThrow(CustomError)6970// Async errors - use rejects71await expect(asyncThrow()).rejects.toThrow('error')72```7374## Promise Assertions7576```ts77// Resolves78await expect(Promise.resolve(1)).resolves.toBe(1)79await expect(fetchData()).resolves.toEqual({ data: true })8081// Rejects82await expect(Promise.reject('error')).rejects.toBe('error')83await expect(failingFetch()).rejects.toThrow()84```8586## Spy/Mock Assertions8788```ts89const fn = vi.fn()90fn('arg1', 'arg2')91fn('arg3')9293expect(fn).toHaveBeenCalled()94expect(fn).toHaveBeenCalledTimes(2)95expect(fn).toHaveBeenCalledWith('arg1', 'arg2')96expect(fn).toHaveBeenLastCalledWith('arg3')97expect(fn).toHaveBeenNthCalledWith(1, 'arg1', 'arg2')9899expect(fn).toHaveReturned()100expect(fn).toHaveReturnedWith(value)101```102103## Asymmetric Matchers104105Use inside `toEqual`, `toHaveBeenCalledWith`, etc:106107```ts108expect({ id: 1, name: 'test' }).toEqual({109id: expect.any(Number),110name: expect.any(String),111})112113expect({ a: 1, b: 2, c: 3 }).toEqual(114expect.objectContaining({ a: 1 })115)116117expect([1, 2, 3, 4]).toEqual(118expect.arrayContaining([1, 3])119)120121expect('hello world').toEqual(122expect.stringContaining('world')123)124125expect('hello world').toEqual(126expect.stringMatching(/world$/)127)128129expect({ value: null }).toEqual({130value: expect.anything() // Matches anything except null/undefined131})132133// Negate with expect.not134expect([1, 2]).toEqual(135expect.not.arrayContaining([3])136)137```138139## Soft Assertions140141Continue test after failure:142143```ts144expect.soft(1).toBe(2) // Marks test failed but continues145expect.soft(2).toBe(3) // Also runs146// All failures reported at end147```148149## Poll Assertions150151Retry until passes:152153```ts154await expect.poll(() => fetchStatus()).toBe('ready')155156await expect.poll(157() => document.querySelector('.element'),158{ interval: 100, timeout: 5000 }159).toBeTruthy()160```161162## Assertion Count163164```ts165test('async assertions', async () => {166expect.assertions(2) // Exactly 2 assertions must run167168await doAsync((data) => {169expect(data).toBeDefined()170expect(data.id).toBe(1)171})172})173174test('at least one', () => {175expect.hasAssertions() // At least 1 assertion must run176})177```178179## Extending Matchers180181```ts182expect.extend({183toBeWithinRange(received, floor, ceiling) {184const pass = received >= floor && received <= ceiling185return {186pass,187message: () =>188`expected ${received} to be within range ${floor} - ${ceiling}`,189}190},191})192193test('custom matcher', () => {194expect(100).toBeWithinRange(90, 110)195})196```197198## Snapshot Assertions199200```ts201expect(data).toMatchSnapshot()202expect(data).toMatchInlineSnapshot(`{ "id": 1 }`)203await expect(result).toMatchFileSnapshot('./expected.json')204205expect(() => throw new Error('fail')).toThrowErrorMatchingSnapshot()206```207208## Key Points209210- Use `toBe` for primitives, `toEqual` for objects/arrays211- `toStrictEqual` checks undefined properties and array sparseness212- Always `await` async assertions (`resolves`, `rejects`, `poll`)213- Use context's `expect` in concurrent tests for correct tracking214- `toThrow` requires wrapping sync code in a function215216<!--217Source references:218- https://vitest.dev/api/expect.html219-->220