vitest-dev/vitest · error · TypeError
toHaveFormValues must be called on a form or a fieldset…
Error message
toHaveFormValues must be called on a form or a fieldset, instead got ${getTag(formElement)} What it means
.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.
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.
Example fix
// before
expect(formWrapperEl).toHaveFormValues({ email: 'a@b.c' })
// after
expect(formWrapperEl.querySelector('form')!).toHaveFormValues({ email: 'a@b.c' }) Defensive patterns
Strategy: type-guard
Validate before calling
const win = el.ownerDocument.defaultView || window
if (!(el instanceof win.HTMLFormElement) && !(el instanceof win.HTMLFieldSetElement)) {
// drill down to the nested <form>
el = el.querySelector('form')!
}
expect(el).toHaveFormValues(expected) Type guard
function isFormLike(el: Element): el is HTMLFormElement | HTMLFieldSetElement {
const win = el.ownerDocument.defaultView || window
return el instanceof win.HTMLFormElement || el instanceof win.HTMLFieldSetElement
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- .toContainHTML() expects a string value, got
- .toHaveDisplayValue() currently does not support input
- .toHaveDisplayValue() currently supports only input…
- Exact option does not support RegExp expected class names
- input with type=checkbox or type=radio cannot be used with…
AI-assisted analysis of vitest-dev/vitest@1fa9837ec2 (2026-08-11).
Data as JSON: /api/errors/5f77490251cbd310.
Report an issue: GitHub.
Appendix: source
Thrown at packages/browser/src/client/tester/expect/toHaveFormValues.ts:31
* copies or substantial portions of the Software.
*/
import type { MatcherResult, MatcherState } from 'vitest'
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> = {}View on GitHub (pinned to 1fa9837ec2)