vitest-dev/vitest · error · Error

Exact option does not support RegExp expected class names

Error message

Exact option does not support RegExp expected class names

What it means

The .toHaveClass() matcher supports an `exact: true` option for ordered/equal comparison, but exact matching is fundamentally incompatible with RegExp class-name expectations (a regex cannot express a precise equality set). Vitest throws when both options.exact and at least one RegExp expected value are present, instead of producing a misleading pass/fail.

Solutions

  1. Remove exact: true when using RegExp class-name expectations.
  2. If you need exact matching, supply literal class-name strings instead of regexes.
  3. Split into two assertions: a regex presence check (no exact) and a string-based exact check.

Example fix

// before
expect(el).toHaveClass([/btn-/, 'active'], { exact: true })
// after
expect(el).toHaveClass([/btn-/, 'active'])  // exact removed
// or with literal strings:
expect(el).toHaveClass(['btn-primary', 'active'], { exact: true })
Defensive patterns

Strategy: validation

Validate before calling

const hasRegex = Array.isArray(expected)
  ? expected.some(c => c instanceof RegExp)
  : expected instanceof RegExp
if (options?.exact && hasRegex) {
  // drop exact, or convert regexes to literal strings
}
expect(el).toHaveClass(expected, options)

Type guard

function isRegExp(v: unknown): v is RegExp {
  return v instanceof RegExp
}

Prevention

When it happens

Trigger: Calling expect(el).toHaveClass([/btn-/], { exact: true }); combining exact: true with a RegExp in either the array or single-argument form.

Common situations: Copying a regex-based assertion and adding exact: true for stricter checks; migrating from CSS-class strings to regex without removing the exact flag.

Related errors


AI-assisted analysis of vitest-dev/vitest@1fa9837ec2 (2026-08-11). Data as JSON: /api/errors/79cc1f6b60587c90. Report an issue: GitHub.

Appendix: source

Thrown at packages/browser/src/client/tester/expect/toHaveClass.ts:42

): MatcherResult {
  const htmlElement = getElementFromUserInput(actual, toHaveClass, this)
  const { expectedClassNames, options } = getExpectedClassNamesAndOptions(params)

  const received = splitClassNames(htmlElement.getAttribute('class'))
  const expected = expectedClassNames.reduce(
    (acc, className) => {
      return acc.concat(
        typeof className === 'string' || !className
          ? splitClassNames(className)
          : className,
      )
    },
    [] as (string | RegExp)[],
  )

  const hasRegExp = expected.some(className => className instanceof RegExp)
  if (options.exact && hasRegExp) {
    throw new Error('Exact option does not support RegExp expected class names')
  }

  if (options.exact) {
    return {
      pass: isSubset(expected, received) && expected.length === received.length,
      message: () => {
        const to = this.isNot ? 'not to' : 'to'
        return getMessage(
          this,
          this.utils.matcherHint(
            `${this.isNot ? '.not' : ''}.toHaveClass`,
            'element',
            this.utils.printExpected(expected.join(' ')),
          ),
          `Expected the element ${to} have EXACTLY defined classes`,
          expected.join(' '),
          'Received',
          received.join(' '),

View on GitHub (pinned to 1fa9837ec2)