{"id":"79cc1f6b60587c90","repo":"vitest-dev/vitest","slug":"exact-option-does-not-support-regexp-expected-clas","errorCode":null,"errorMessage":"Exact option does not support RegExp expected class names","messagePattern":"Exact option does not support RegExp expected class names","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/browser/src/client/tester/expect/toHaveClass.ts","lineNumber":42,"sourceCode":"): MatcherResult {\n  const htmlElement = getElementFromUserInput(actual, toHaveClass, this)\n  const { expectedClassNames, options } = getExpectedClassNamesAndOptions(params)\n\n  const received = splitClassNames(htmlElement.getAttribute('class'))\n  const expected = expectedClassNames.reduce(\n    (acc, className) => {\n      return acc.concat(\n        typeof className === 'string' || !className\n          ? splitClassNames(className)\n          : className,\n      )\n    },\n    [] as (string | RegExp)[],\n  )\n\n  const hasRegExp = expected.some(className => className instanceof RegExp)\n  if (options.exact && hasRegExp) {\n    throw new Error('Exact option does not support RegExp expected class names')\n  }\n\n  if (options.exact) {\n    return {\n      pass: isSubset(expected, received) && expected.length === received.length,\n      message: () => {\n        const to = this.isNot ? 'not to' : 'to'\n        return getMessage(\n          this,\n          this.utils.matcherHint(\n            `${this.isNot ? '.not' : ''}.toHaveClass`,\n            'element',\n            this.utils.printExpected(expected.join(' ')),\n          ),\n          `Expected the element ${to} have EXACTLY defined classes`,\n          expected.join(' '),\n          'Received',\n          received.join(' '),","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/vitest-dev/vitest/blob/d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09/packages/browser/src/client/tester/expect/toHaveClass.ts#L24-L60","documentation":"Thrown by toHaveClass (packages/browser/src/client/tester/expect/toHaveClass.ts:40-43) when the { exact: true } option is combined with one or more RegExp expected class names. Exact mode (lines 45-63) requires the expected class set to equal the received class set by length and content, which is meaningless for a RegExp (a pattern has no fixed length/count), so the combination is rejected as a hard error rather than silently producing a confusing result.","triggerScenarios":"Calling expect(el).toHaveClass(/btn-.*/, { exact: true }) or expect(el).toHaveClass('active', /icon-\\w+/, { exact: true }).","commonSituations":"Copy-paste from a string-based exact assertion where a regex was later substituted; mixing exact class-set checks with flexible pattern matches.","solutions":["Drop exact when using regex: expect(el).toHaveClass(/btn-.*/).","If you need exactness, convert the regex to literal class names: expect(el).toHaveClass('btn-primary', 'btn-lg', { exact: true }).","Split into two assertions: a regex match without exact, plus a separate exact string check."],"exampleFix":"// before\nexpect(el).toHaveClass(/btn-\\w+/, { exact: true })\n// after\nexpect(el).toHaveClass('btn-primary', 'btn-lg', { exact: true })","handlingStrategy":"validation","validationCode":"function hasRegExpExpected(classes: (string | RegExp)[]): boolean {\n  return classes.some(c => c instanceof RegExp)\n}\nconst expected: (string | RegExp)[] = [/btn-\\w+/]\nconst exact = !hasRegExpExpected(expected)\nexpect(el).toHaveClass(...(exact ? expected.map(String) : expected), { exact })","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never combine { exact: true } with RegExp class names.","Convert regexes to literal class names when exact set comparison is needed."],"tags":["browser","expect","matcher","tohaveclass","regex","exact-option"],"analyzedSha":"d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09","analyzedAt":"2026-08-03T20:23:56.861Z","schemaVersion":2}