{"record":{"id":"fcaef83c3d55b7f8","repo":"jestjs/jest","slug":"expected-is-not-a-string-or-a-regexp","errorCode":null,"errorMessage":"Expected is not a String or a RegExp","messagePattern":"Expected is not a String or a RegExp","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/expect/src/asymmetricMatchers.ts","lineNumber":326,"sourceCode":"  asymmetricMatch(other: unknown) {\n    const result = isA<string>('String', other) && other.includes(this.sample);\n\n    return this.inverse ? !result : result;\n  }\n\n  toString() {\n    return `String${this.inverse ? 'Not' : ''}Containing`;\n  }\n\n  override getExpectedType() {\n    return 'string';\n  }\n}\n\nclass StringMatching extends AsymmetricMatcher<RegExp> {\n  constructor(sample: string | RegExp, inverse = false) {\n    if (!isA('String', sample) && !isA('RegExp', sample)) {\n      throw new Error('Expected is not a String or a RegExp');\n    }\n    super(new RegExp(sample), inverse);\n  }\n\n  asymmetricMatch(other: unknown) {\n    const result = isA<string>('String', other) && this.sample.test(other);\n\n    return this.inverse ? !result : result;\n  }\n\n  toString() {\n    return `String${this.inverse ? 'Not' : ''}Matching`;\n  }\n\n  override getExpectedType() {\n    return 'string';\n  }\n}","sourceCodeStart":308,"sourceCodeEnd":344,"githubUrl":"https://github.com/jestjs/jest/blob/8e6d128e4a278059ecddecaa97400b04c8ae5fd9/packages/expect/src/asymmetricMatchers.ts#L308-L344","documentation":"stringMatching / stringNotMatching accept either a string (treated as a regex source) or a RegExp. The constructor throws an Error if the sample is neither — e.g. a number, object, or undefined. Because the constructor wraps the sample in `new RegExp(sample)`, an invalid type would produce a confusing RegExp error, so this guard rejects it early with a clear message.","triggerScenarios":"Calling `expect.stringMatching(value)` where value is not a string and not a RegExp (e.g. a number, null, object, or a Date). Thrown at construction time.","commonSituations":"Passing a non-string primitive; forgetting to quote a literal pattern; passing an object whose toString is not the intended pattern; mixing up stringMatching (regex) with stringContaining (substring).","solutions":["Pass a RegExp or a string regex source: `expect.stringMatching(/^foo/)` or `expect.stringMatching('^foo')`.","If you meant a literal substring, use `expect.stringContaining('foo')` instead.","Coerce unknown inputs to a string before passing, if a string pattern is acceptable."],"exampleFix":"// before\nexpect(msg).toEqual(expect.stringMatching(123)); // number, not String/RegExp\n\n// after\nexpect(msg).toEqual(expect.stringMatching(/^\\d+$/));\n// or substring:\nexpect(msg).toEqual(expect.stringContaining('123'));","handlingStrategy":"type-guard","validationCode":"function stringMatchingSafe(sample) {\n  if (typeof sample !== 'string' && !(sample instanceof RegExp)) {\n    throw new TypeError('stringMatching requires a string or RegExp');\n  }\n  return expect.stringMatching(sample);\n}","typeGuard":"function isStringOrRegExp(v: unknown): v is string | RegExp {\n  return typeof v === 'string' || v instanceof RegExp;\n}\n\nconst m = isStringOrRegExp(sample) ? expect.stringMatching(sample) : expect.anything();","tryCatchPattern":null,"preventionTips":["Pass a RegExp or a regex-source string to stringMatching.","Use stringContaining for plain substrings.","Validate dynamic patterns before constructing the matcher."],"tags":["expect","asymmetric-matcher","typeerror","api-misuse"],"backgroundTag":null,"analyzedSha":"8e6d128e4a278059ecddecaa97400b04c8ae5fd9","analyzedAt":"2026-08-10T18:11:27.960Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}