vitest-dev/vitest · error · TypeError
toHaveFormValues must be called with an object of expected…
Error message
toHaveFormValues must be called with an object of expected form values. Got ${expectedValues} What it means
Thrown by the `toHaveFormValues` matcher when the second argument (`expectedValues`) is not a plain object. The matcher validates the argument with `!expectedValues || typeof expectedValues !== 'object'` before reading form fields, because the comparison logic iterates `Object.entries(expectedValues)` to match each key against the form's collected values. Passing a primitive, null, or undefined makes the matcher's per-field comparison meaningless, so it refuses to run.
Solutions
- Pass a plain object mapping each form field's `name` attribute to its expected value, e.g. `expect(form).toHaveFormValues({ email: 'a@b.com', count: 2 })`.
- If you have a JSON string, parse it first: `expect(form).toHaveFormValues(JSON.parse(str))`.
- Confirm each object key matches the DOM element's `name` attribute (not its `id`); unmatched keys cause assertion failure, not this error.
- For a single field use `toHaveValue` instead of `toHaveFormValues`.
Example fix
// before
expect(form).toHaveFormValues('a@b.com')
// after
expect(form).toHaveFormValues({ email: 'a@b.com' }) Defensive patterns
Strategy: validation
Validate before calling
// before calling the matcher
function assertFormValuesObject(v: unknown): asserts v is Record<string, unknown> {
if (!v || typeof v !== 'object' || Array.isArray(v)) {
throw new TypeError('toHaveFormValues expects a plain object of { fieldName: value }')
}
}
assertFormValuesObject(expected)
expect(form).toHaveFormValues(expected) Type guard
function isFormValuesObject(v: unknown): v is Record<string, unknown> {
return !!v && typeof v === 'object' && !Array.isArray(v)
} Prevention
- Always pass a `{ name: value }` record; never a scalar.
- If the expected data comes from JSON, parse it before passing.
- Let TypeScript's `Record<string, unknown>` parameter type catch mismatches at compile time.
When it happens
Trigger: Calling `expect(form).toHaveFormValues(null)`, `.toHaveFormValues(undefined)`, `.toHaveFormValues('email')` (string), `.toHaveFormValues(5)` (number), or omitting the argument entirely so it defaults to undefined. The check at toHaveFormValues.ts:34 fires before any DOM value is read.
Common situations: Forgetting the expected-values argument; passing a serialized JSON string instead of a parsed object; refactoring a test and accidentally passing the expected value of a single field instead of a `{ name: value }` record; copy-pasting a `toHaveValue` call (which takes a scalar) into a `toHaveFormValues` call without wrapping it.
Related errors
- expected selection must be a string or undefined
- input with type=checkbox or type=radio cannot be used with…
- Multiple form elements with the same name must be of the…
- received value must a Node or a Locator that returns a Node.
- received value must an HTMLElement or an SVGElement or a…
AI-assisted analysis of vitest-dev/vitest@1fa9837ec2 (2026-08-11).
Data as JSON: /api/errors/9ad86eaac9c2bfa7.
Report an issue: GitHub.
Appendix: 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 1fa9837ec2)