new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Vitest · Guide · all subjects

advanced/matchers

81 notes in this subject, read out of this brain and free to use. This is page 2 of 2.

toThrow matcher for exception testing

The toThrow matcher verifies that a function throws an error. You need to wrap the call in another function so that Vitest can catch the error instead of letting it crash the test. For example, expect(() => compileCode('')).toThrow().

toThrow with error message matching

The toThrow matcher can check the error message as a string or with a regex. For example, expect(() => compileCode('')).toThrow('Cannot compile empty string') or expect(() => compileCode('')).toThrow(/empty string/).

When to use vi.defineHelper

Use vi.defineHelper whenever a reusable assertion helper calls expect more than once. This applies to domain-specific helpers like expectValidJWT or any block of expect calls that would otherwise be inlined into every test. A failure in any of the inner expect calls is reported against the helper function's call site in the test.

vi.defineHelper wraps assertion helpers to fix stack traces

vi.defineHelper is a Vitest function that wraps custom assertion helper functions so that when an assertion fails, the stack trace points to the test line that called the helper rather than the line inside the helper function itself. This makes debugging easier by identifying the actual call site of the failing assertion instead of the helper's internals.

vi.defineHelper single assertion example

import { expect, test, vi } from 'vitest' const assertPair = vi.defineHelper((a: unknown, b: unknown) => { expect(a).toEqual(b) // ❌ failure does NOT point here }) test('example', () => { assertPair('left', 'right') // ✅ failure points here })

vi.defineHelper multiple assertions example

import { expect, test, vi } from 'vitest' const expectValidUser = vi.defineHelper((user: unknown) => { expect(user).toHaveProperty('id') expect(user).toHaveProperty('email') expect(user.email).toMatch(/@/) }) test('returns a valid user', async () => { const user = await fetchUser('alice') expectValidUser(user) })

schemaMatching for mock call assertions

expect.schemaMatching is useful for asserting that a mock was called with data conforming to a schema, without spelling out every field. It is especially useful for validating the format of generated fields like UUIDs or timestamps without predicting exact values.

expect.schemaMatching asymmetric matcher

expect.schemaMatching is an asymmetric matcher introduced in Vitest 4.0.0 that takes any Standard Schema v1 object and passes if the value conforms to it. It can be composed inside any equality check the same way as expect.any or expect.stringMatching.

Mock call assertion with schemaMatching example

Example showing how to verify a mock was called with data conforming to a schema: ```ts import { expect, test, vi } from 'vitest' import { z } from 'zod' const UserSchema = z.object({ id: z.string().uuid(), email: z.string().email(), createdAt: z.date(), }) test('persists a valid user', () => { const repo = { save: vi.fn() } registerUser(repo, { email: 'a@b.com' }) expect(repo.save).toHaveBeenCalledWith(expect.schemaMatching(UserSchema)) }) ```

schemaMatching works with Zod, Valibot, and ArkType

expect.schemaMatching is compatible with any Standard Schema v1 library, including Zod, Valibot, and ArkType. The matcher validates that a value conforms to schemas defined with these libraries.

schemaMatching composable in equality checks

expect.schemaMatching can be composed inside toEqual, toStrictEqual, toMatchObject, toContainEqual, toThrow, toHaveBeenCalledWith, toHaveReturnedWith, and toHaveBeenResolvedWith assertions.

Schema-driven assertions with schemaMatching example

Example showing how to use expect.schemaMatching with Zod: ```ts import { expect, test } from 'vitest' import { z } from 'zod' test('email validation', () => { const user = { email: 'john@example.com' } expect(user).toEqual({ email: expect.schemaMatching(z.string().email()), }) }) ```

Why toBeTruthy doesn't narrow types

expect(x).toBeTruthy() and expect(x).toBeDefined() throw at runtime when the value is missing but do not narrow the TypeScript type. They don't narrow because their TypeScript signature returns void rather than the special 'asserts' form that expect.assert uses.

Type narrowing pattern with Array.find()

When using Array.find() which returns T | undefined, use expect.assert(job) to throw if undefined and narrow the type from Job | undefined to Job for subsequent operations.

Type narrowing pattern with Map.get()

When retrieving values from a Map that returns T | undefined, use expect.assert(user) after cache.get() to throw if undefined and narrow the type so subsequent accesses do not require non-null assertions.

expect.assert for type narrowing

expect.assert() throws at runtime and narrows the TypeScript type. It replaces unsafe casts with 'as', non-null assertions with '!', or misleading runtime checks like expect(x).toBeTruthy(). The same call serves both runtime checking and type narrowing purposes.

expect.assert with boolean expressions

expect.assert() accepts any boolean expression and applies the same narrowing TypeScript would do for an if branch. This covers typeof and instanceof checks, allowing type narrowing based on conditional logic.

expect.assert pre-built helpers from chai

Pre-built helper functions are available via the expect.assert namespace: isDefined(value) narrows away undefined, isString(value) narrows to string, and instanceOf(value, Constructor) narrows to the Constructor type.

toThrow with empty string matches any error message

In Vitest 5.0, toThrow() and toThrowError() now treat an empty string argument as a substring match like any other substring. An empty string is contained in every message, so it matches any thrown error. In Vitest 4, an empty string was special-cased to /^$/ to match only empty error messages. To assert an empty message, use the pattern /^$/ explicitly.

Assertion types expose return and received types in Vitest 5.0

In Vitest 5.0, assertion interfaces use two type parameters: R is the matcher return type (void for sync, Promise<void> for async) and T is the received value type. Custom matchers should augment Matchers<R, T> interface. References to Assertion types now require both parameters: Assertion<void, string> for sync or Assertion<Promise<void>, string> for async. Vitest no longer reads declarations from global jest.Matchers interface.

expect.poll rejects when it times out

In Vitest 5.0, expect.poll() now rejects when its callback or the polled assertion does not settle within timeout. Previously, a callback resolving after the deadline could still succeed. The callback now receives an AbortSignal that aborts when timeout elapses, allowing cancellation of in-flight work. It fails with 'expect.poll() function didn't resolve in time.' or 'expect.poll() assertion didn't resolve in time.'

Give your agent this brain