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

  1. Pass exact class tokens: `await expect(locator).toContainClass(['btn', 'theme-dark'])`.
  2. If you genuinely need pattern matching on the class attribute, switch matcher: `await expect(locator).toHaveAttribute('class', /theme-/)`.
  3. 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

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


AI-assisted analysis of microsoft/playwright@deda92d15e (2026-08-21). Data as JSON: /api/errors/e7dd7e571cf47c76. Report an issue: GitHub.