{"record":{"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/1fa9837ec26533512fdcad8baebf249771bd340a/packages/browser/src/client/tester/expect/toHaveFormValues.ts#L13-L49","documentation":".toHaveFormValues() reads named form controls, which only a FORM or FIELDSET element owns. If the target element has any other tag, the matcher throws a TypeError with the actual tag name, because there is no form-control collection to enumerate. The check uses the document's own HTMLFormElement/HTMLFieldSetElement constructors to support iframes and jsdom.","triggerScenarios":"Calling expect(divEl).toHaveFormValues({...}); calling on a section/article that wraps a form but is not itself a form/fieldset; passing the wrong element resolved from a Locator.","commonSituations":"Targeting a styled wrapper instead of the real <form>; copy-pasting form assertions onto custom form components whose root tag is a div; refactors that changed the queried selector.","solutions":["Query the actual <form> or <fieldset> element (e.g. container.querySelector('form')).","If the component root is a div, drill down to the nested form before asserting.","For custom elements, assert on individual fields with toHaveValue instead."],"exampleFix":"// before\nexpect(formWrapperEl).toHaveFormValues({ email: 'a@b.c' })\n// after\nexpect(formWrapperEl.querySelector('form')!).toHaveFormValues({ email: 'a@b.c' })","handlingStrategy":"type-guard","validationCode":"const win = el.ownerDocument.defaultView || window\nif (!(el instanceof win.HTMLFormElement) && !(el instanceof win.HTMLFieldSetElement)) {\n  // drill down to the nested <form>\n  el = el.querySelector('form')!\n}\nexpect(el).toHaveFormValues(expected)","typeGuard":"function isFormLike(el: Element): el is HTMLFormElement | HTMLFieldSetElement {\n  const win = el.ownerDocument.defaultView || window\n  return el instanceof win.HTMLFormElement || el instanceof win.HTMLFieldSetElement\n}","tryCatchPattern":null,"preventionTips":["Pass the actual <form>/<fieldset> element, not a wrapper div.","In shared helpers, query the nested form before asserting.","Use toHaveValue on individual fields for custom-element forms."],"tags":["browser","expect","matcher","form","type-guard"],"backgroundTag":null,"analyzedSha":"1fa9837ec26533512fdcad8baebf249771bd340a","analyzedAt":"2026-08-11T16:11:39.638Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}