{"id":"5f77490251cbd310","repo":"vitest-dev/vitest","slug":"tohaveformvalues-must-be-called-on-a-form-or-a-fie","errorCode":null,"errorMessage":"toHaveFormValues must be called on a form or a fieldset, instead got ${getTag(formElement)}","messagePattern":"toHaveFormValues must be called on a form or a fieldset, instead got (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/browser/src/client/tester/expect/toHaveFormValues.ts","lineNumber":31,"sourceCode":" * copies or substantial portions of the Software.\n */\n\nimport type { MatcherResult, MatcherState } from 'vitest'\nimport 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> = {}","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/vitest-dev/vitest/blob/d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09/packages/browser/src/client/tester/expect/toHaveFormValues.ts#L13-L49","documentation":"Thrown by the `toHaveFormValues` matcher when the received element is not an HTMLFormElement or HTMLFieldSetElement. The matcher inspects the DOM element returned from the user's locator/element input and checks it against `defaultView.HTMLFieldSetElement`/`HTMLFormElement` at toHaveFormValues.ts:30; any other tag fails. This is a precondition violation, not an assertion failure — the matcher cannot read form values off a non-form node.","triggerScenarios":"Calling `expect(div).toHaveFormValues({...})`, `expect(page.getByRole('textbox')).toHaveFormValues(...)`, or passing any element whose tag is not `<form>` or `<fieldset>`. Also triggered when a Locator resolves to a child input inside the form instead of the form/fieldset itself.","commonSituations":"Developers coming from jest-dom where they pass a form *child* (e.g. an `<input>`) rather than the wrapping `<form>`. Also happens when `page.getByRole('form')` matches nothing and a fallback element slips through, or when fieldset detection fails because the element lives in a different document (shadow DOM/iframe) whose `defaultView` differs.","solutions":["Pass the `<form>` or `<fieldset>` element/locator to `expect()` instead of an input, select, or div inside it.","If using a Locator, ensure it resolves to the form: `page.getByRole('form')` or `page.locator('form#login')`.","If the element is inside a shadow root or iframe, resolve the form in that document context before calling the matcher."],"exampleFix":"// before\nconst input = page.getByRole('textbox', { name: 'email' })\nexpect(input).toHaveFormValues({ email: 'a@b.com' })\n\n// after\nconst form = page.getByRole('form', { name: 'Sign in' })\nexpect(form).toHaveFormValues({ email: 'a@b.com' })","handlingStrategy":"validation","validationCode":"function isFormLike(el: Element | null | undefined, view: Window = window): boolean {\n  return !!el && (el instanceof view.HTMLFormElement || el instanceof view.HTMLFieldSetElement)\n}\n// before calling:\nif (!isFormLike(target)) throw new Error('pass a <form>/<fieldset> to toHaveFormValues')","typeGuard":"function isFormOrFieldSet(el: unknown, view: Window = window): el is HTMLFormElement | HTMLFieldSetElement {\n  return el instanceof view.HTMLFormElement || el instanceof view.HTMLFieldSetElement\n}","tryCatchPattern":null,"preventionTips":["Always pass the form/fieldset element, not its children, to toHaveFormValues.","Use role-based locators: page.getByRole('form') to target the form.","Add a TypeScript generic on a helper to constrain the element type."],"tags":["browser","expect-matcher","dom","tohaveformvalues","type-validation"],"analyzedSha":"d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09","analyzedAt":"2026-08-03T20:23:56.861Z","schemaVersion":2}