{"record":{"id":"9ad86eaac9c2bfa7","repo":"vitest-dev/vitest","slug":"tohaveformvalues-must-be-called-with-an-object-of","errorCode":null,"errorMessage":"toHaveFormValues must be called with an object of expected form values. Got ${expectedValues}","messagePattern":"toHaveFormValues must be called with an object of expected form values\\. Got (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/browser/src/client/tester/expect/toHaveFormValues.ts","lineNumber":35,"sourceCode":"import type { Locator } from '../locators'\nimport { cssEscape } from 'ivya/utils'\nimport { arrayAsSetComparison, getElementFromUserInput, getSingleElementValue, getTag } from './utils'\n\nexport default function toHaveFormValues(\n  this: MatcherState,\n  actual: Element | Locator,\n  expectedValues: Record<string, unknown>,\n): MatcherResult {\n  const formElement = getElementFromUserInput(actual, toHaveFormValues, this)\n\n  const defaultView = formElement.ownerDocument.defaultView || window\n\n  if (!(formElement instanceof defaultView.HTMLFieldSetElement) && !(formElement instanceof defaultView.HTMLFormElement)) {\n    throw new TypeError(`toHaveFormValues must be called on a form or a fieldset, instead got ${getTag(formElement)}`)\n  }\n\n  if (!expectedValues || typeof expectedValues !== 'object') {\n    throw new TypeError(\n      `toHaveFormValues must be called with an object of expected form values. Got ${expectedValues}`,\n    )\n  }\n\n  const formValues = getAllFormValues(formElement)\n  return {\n    pass: Object.entries(expectedValues).every(([name, expectedValue]) =>\n      this.equals(formValues[name], expectedValue, [arrayAsSetComparison, ...this.customTesters]),\n    ),\n    message: () => {\n      const to = this.isNot ? 'not to' : 'to'\n      const matcher = `${this.isNot ? '.not' : ''}.toHaveFormValues`\n\n      const commonKeyValues: Record<string, unknown> = {}\n      for (const key in formValues) {\n        if (!Object.hasOwn(expectedValues, key)) {\n          continue\n        }","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/vitest-dev/vitest/blob/1fa9837ec26533512fdcad8baebf249771bd340a/packages/browser/src/client/tester/expect/toHaveFormValues.ts#L17-L53","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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`."],"exampleFix":"// before\nexpect(form).toHaveFormValues('a@b.com')\n\n// after\nexpect(form).toHaveFormValues({ email: 'a@b.com' })","handlingStrategy":"validation","validationCode":"// before calling the matcher\nfunction assertFormValuesObject(v: unknown): asserts v is Record<string, unknown> {\n  if (!v || typeof v !== 'object' || Array.isArray(v)) {\n    throw new TypeError('toHaveFormValues expects a plain object of { fieldName: value }')\n  }\n}\nassertFormValuesObject(expected)\nexpect(form).toHaveFormValues(expected)","typeGuard":"function isFormValuesObject(v: unknown): v is Record<string, unknown> {\n  return !!v && typeof v === 'object' && !Array.isArray(v)\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["matcher","argument-validation","browser","form"],"backgroundTag":null,"analyzedSha":"1fa9837ec26533512fdcad8baebf249771bd340a","analyzedAt":"2026-08-11T16:11:39.638Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}