vitest-dev/vitest · error · TypeError

toHaveFormValues must be called with an object of expected f

Error message

toHaveFormValues must be called with an object of expected form values. Got ${expectedValues}

What it means

Thrown by `toHaveFormValues` at toHaveFormValues.ts:34-37 when the second argument is not a non-null object. The matcher signature requires `Record<string, unknown>`; passing `undefined`, `null`, a primitive, an array, or omitting the argument entirely fails the `typeof expectedValues !== 'object'` guard.

Source

Thrown at packages/browser/src/client/tester/expect/toHaveFormValues.ts:35

import type { Locator } from '../locators'
import { cssEscape } from 'ivya/utils'
import { arrayAsSetComparison, getElementFromUserInput, getSingleElementValue, getTag } from './utils'

export default function toHaveFormValues(
  this: MatcherState,
  actual: Element | Locator,
  expectedValues: Record<string, unknown>,
): MatcherResult {
  const formElement = getElementFromUserInput(actual, toHaveFormValues, this)

  const defaultView = formElement.ownerDocument.defaultView || window

  if (!(formElement instanceof defaultView.HTMLFieldSetElement) && !(formElement instanceof defaultView.HTMLFormElement)) {
    throw new TypeError(`toHaveFormValues must be called on a form or a fieldset, instead got ${getTag(formElement)}`)
  }

  if (!expectedValues || typeof expectedValues !== 'object') {
    throw new TypeError(
      `toHaveFormValues must be called with an object of expected form values. Got ${expectedValues}`,
    )
  }

  const formValues = getAllFormValues(formElement)
  return {
    pass: Object.entries(expectedValues).every(([name, expectedValue]) =>
      this.equals(formValues[name], expectedValue, [arrayAsSetComparison, ...this.customTesters]),
    ),
    message: () => {
      const to = this.isNot ? 'not to' : 'to'
      const matcher = `${this.isNot ? '.not' : ''}.toHaveFormValues`

      const commonKeyValues: Record<string, unknown> = {}
      for (const key in formValues) {
        if (!Object.hasOwn(expectedValues, key)) {
          continue
        }

View on GitHub (pinned to d568f8ce37)

Solutions

  1. Pass a plain object mapping field names to expected values: `expect(form).toHaveFormValues({ email: 'a@b.com', count: 2 })`.
  2. If building expected values dynamically, default to `{}` instead of `undefined`: `expect(form).toHaveFormValues(expected ?? {})`.
  3. Add a TypeScript annotation (`const expected: Record<string, unknown> = ...`) so the compiler catches the mismatch.

Example fix

// before
expect(form).toHaveFormValues(buildExpected()) // buildExpected() may return undefined

// after
const expected = buildExpected() ?? {}
expect(form).toHaveFormValues(expected)
Defensive patterns

Strategy: validation

Validate before calling

function isValuesObject(v: unknown): v is Record<string, unknown> {
  return v !== null && typeof v === 'object' && !Array.isArray(v)
}
const safe = isValuesObject(expected) ? expected : {}

Type guard

function isValuesObject(v: unknown): v is Record<string, unknown> {
  return v !== null && typeof v === 'object' && !Array.isArray(v)
}

Prevention

When it happens

Trigger: Calling `expect(form).toHaveFormValues()` (no second arg), `expect(form).toHaveFormValues(null)`, `expect(form).toHaveFormValues('email')`, or `expect(form).toHaveFormValues(['email'])`. Also triggered by passing a value typed `any` that is actually a string at runtime.

Common situations: Migrating from `toHaveValue` and assuming the second arg is a string. Constructing expected values from a function that can return `undefined`. JavaScript users (no TS compile-time check) passing the wrong shape.

Related errors


AI-assisted analysis of vitest-dev/vitest@d568f8ce37 (2026-08-03). Data as JSON: /data/errors/9ad86eaac9c2bfa7.json. Report an issue: GitHub.