{"record":{"id":"e7dd7e571cf47c76","repo":"microsoft/playwright","slug":"expected-argument-in-tocontainclass-cannot-conta","errorCode":null,"errorMessage":"\"expected\" argument in toContainClass cannot contain RegExp values","messagePattern":"\"expected\" argument in toContainClass cannot contain RegExp values","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/playwright/src/matchers/matchers.ts","lineNumber":315,"sourceCode":"      return await locator._expect('to.have.class.array', { expectedText, isNot, timeout, signal, title: this.title });\n    }, expected, options);\n  } else {\n    return toMatchText.call(this, 'toHaveClass', locator, 'Locator', async (isNot, timeout, signal) => {\n      const expectedText = serializeExpectedTextValues([expected]);\n      return await locator._expect('to.have.class', { expectedText, isNot, timeout, signal, title: this.title });\n    }, expected, options);\n  }\n}\n\nexport function toContainClass(\n  this: ExpectMatcherStateInternal,\n  locator: LocatorEx,\n  expected: string | string[],\n  options?: { timeout?: number, signal?: AbortSignal },\n) {\n  if (Array.isArray(expected)) {\n    if (expected.some(e => isRegExp(e)))\n      throw new Error(`\"expected\" argument in toContainClass cannot contain RegExp values`);\n    return toEqual.call(this, 'toContainClass', locator, 'Locator', async (isNot, timeout, signal) => {\n      const expectedText = serializeExpectedTextValues(expected);\n      return await locator._expect('to.contain.class.array', { expectedText, isNot, timeout, signal, title: this.title });\n    }, expected, options);\n  } else {\n    if (isRegExp(expected))\n      throw new Error(`\"expected\" argument in toContainClass cannot be a RegExp value`);\n    return toMatchText.call(this, 'toContainClass', locator, 'Locator', async (isNot, timeout, signal) => {\n      const expectedText = serializeExpectedTextValues([expected]);\n      return await locator._expect('to.contain.class', { expectedText, isNot, timeout, signal, title: this.title });\n    }, expected, options);\n  }\n}\n\nexport function toHaveCount(\n  this: ExpectMatcherStateInternal,\n  locator: LocatorEx,\n  expected: number,","sourceCodeStart":297,"sourceCodeEnd":333,"githubUrl":"https://github.com/microsoft/playwright/blob/deda92d15e7d771aacaae47eb2b6e47a562c30ff/packages/playwright/src/matchers/matchers.ts#L297-L333","documentation":"expect(locator).toContainClass() only accepts exact class-name strings (or an array of them); passing a RegExp inside the array is rejected up front in matchers.ts:313-315. Class containment is a token-membership check ('to.contain.class.array' with serializeExpectedTextValues), which has no regex semantics, so Playwright fails fast on the caller's invalid argument instead of silently mis-matching.","triggerScenarios":"Calling `await expect(locator).toContainClass(['btn', /^theme-/])` or any array where `expected.some(e => isRegExp(e))` is true. TypeScript flags this at compile time (expected: string | string[]), so it is most often reached from JS tests or values cast with `as any`/built dynamically.","commonSituations":"Developers assuming toContainClass mirrors toHaveText's RegExp support; migrating a helper that builds expected values from user input or fixtures where a regex slips into the array; dynamically generated class lists (e.g. `theme-dark`, hashed Tailwind classes) tempting a regex match.","solutions":["Pass exact class tokens: `await expect(locator).toContainClass(['btn', 'theme-dark'])`.","If you genuinely need pattern matching on the class attribute, switch matcher: `await expect(locator).toHaveAttribute('class', /theme-/)`.","Guard dynamic inputs before the assertion so regexes never reach the matcher (see typeGuard)."],"exampleFix":"// before\nawait expect(page.getByRole('button')).toContainClass(['btn', /^theme-/]);\n// Error: \"expected\" argument in toContainClass cannot contain RegExp values\n\n// after\nawait expect(page.getByRole('button')).toContainClass(['btn', 'theme-dark']);\n// or match the attribute with a regex:\nawait expect(page.getByRole('button')).toHaveAttribute('class', /theme-/);","handlingStrategy":"type-guard","validationCode":"const expectedClasses: unknown[] = getExpectedFromFixture();\nif (expectedClasses.some(e => e instanceof RegExp))\n  throw new Error('toContainClass takes exact class names, not regexes');\nawait expect(locator).toContainClass(expectedClasses as string[]);","typeGuard":"function isClassNameList(value: unknown): value is string | string[] {\n  if (typeof value === 'string') return true;\n  return Array.isArray(value) && value.every(item => typeof item === 'string');\n}\n\n// usage\nif (!isClassNameList(expected)) throw new Error(`Invalid classes for toContainClass: ${String(expected)}`);\nawait expect(locator).toContainClass(expected);","tryCatchPattern":null,"preventionTips":["Rely on the TypeScript signatures (string | string[]) — avoid `as any` around matchers.","Use exact class tokens from your design system instead of patterns.","Reach for toHaveAttribute('class', /regex/) when you actually need pattern matching."],"tags":["assertions","expect","matchers","locator","regex","typescript"],"backgroundTag":"assertion-argument-type-mismatch","analyzedSha":"deda92d15e7d771aacaae47eb2b6e47a562c30ff","analyzedAt":"2026-08-21T16:56:32.694Z","contentChangedAt":"2026-08-21T16:56:32.694Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}