microsoft/playwright · error · Error
"expected" argument in toContainClass cannot contain RegExp
Error message
"expected" argument in toContainClass cannot contain RegExp values
What it means
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.
Source
Thrown at packages/playwright/src/matchers/matchers.ts:315
return await locator._expect('to.have.class.array', { expectedText, isNot, timeout, signal, title: this.title });
}, expected, options);
} else {
return toMatchText.call(this, 'toHaveClass', locator, 'Locator', async (isNot, timeout, signal) => {
const expectedText = serializeExpectedTextValues([expected]);
return await locator._expect('to.have.class', { expectedText, isNot, timeout, signal, title: this.title });
}, expected, options);
}
}
export function toContainClass(
this: ExpectMatcherStateInternal,
locator: LocatorEx,
expected: string | string[],
options?: { timeout?: number, signal?: AbortSignal },
) {
if (Array.isArray(expected)) {
if (expected.some(e => isRegExp(e)))
throw new Error(`"expected" argument in toContainClass cannot contain RegExp values`);
return toEqual.call(this, 'toContainClass', locator, 'Locator', async (isNot, timeout, signal) => {
const expectedText = serializeExpectedTextValues(expected);
return await locator._expect('to.contain.class.array', { expectedText, isNot, timeout, signal, title: this.title });
}, expected, options);
} else {
if (isRegExp(expected))
throw new Error(`"expected" argument in toContainClass cannot be a RegExp value`);
return toMatchText.call(this, 'toContainClass', locator, 'Locator', async (isNot, timeout, signal) => {
const expectedText = serializeExpectedTextValues([expected]);
return await locator._expect('to.contain.class', { expectedText, isNot, timeout, signal, title: this.title });
}, expected, options);
}
}
export function toHaveCount(
this: ExpectMatcherStateInternal,
locator: LocatorEx,
expected: number,View on GitHub (pinned to deda92d15e)
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).
Example fix
// before
await expect(page.getByRole('button')).toContainClass(['btn', /^theme-/]);
// Error: "expected" argument in toContainClass cannot contain RegExp values
// after
await expect(page.getByRole('button')).toContainClass(['btn', 'theme-dark']);
// or match the attribute with a regex:
await expect(page.getByRole('button')).toHaveAttribute('class', /theme-/); Defensive patterns
Strategy: type-guard
Validate before calling
const expectedClasses: unknown[] = getExpectedFromFixture();
if (expectedClasses.some(e => e instanceof RegExp))
throw new Error('toContainClass takes exact class names, not regexes');
await expect(locator).toContainClass(expectedClasses as string[]); Type guard
function isClassNameList(value: unknown): value is string | string[] {
if (typeof value === 'string') return true;
return Array.isArray(value) && value.every(item => typeof item === 'string');
}
// usage
if (!isClassNameList(expected)) throw new Error(`Invalid classes for toContainClass: ${String(expected)}`);
await expect(locator).toContainClass(expected); Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- "expected" argument in toContainClass cannot be a RegExp val
- "role" argument in toHaveRole must be a string
- "${param.target}" does not match any elements.
- Ref ${param.target} not found in the current page snapshot.
- Error while parsing selector `${selector}`: ${e.message}
AI-assisted analysis of microsoft/playwright@deda92d15e (2026-08-21).
Data as JSON: /api/errors/e7dd7e571cf47c76.
Report an issue: GitHub.