{"record":{"id":"2ac37afb6a23af58","repo":"jestjs/jest","slug":"expected-is-not-a-string","errorCode":null,"errorMessage":"Expected is not a string","messagePattern":"Expected is not a string","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/expect/src/asymmetricMatchers.ts","lineNumber":303,"sourceCode":"      }\n    }\n\n    return this.inverse ? !result : result;\n  }\n\n  toString() {\n    return `Object${this.inverse ? 'Not' : ''}Containing`;\n  }\n\n  override getExpectedType() {\n    return 'object';\n  }\n}\n\nclass StringContaining extends AsymmetricMatcher<string> {\n  constructor(sample: string, inverse = false) {\n    if (!isA('String', sample)) {\n      throw new Error('Expected is not a string');\n    }\n    super(sample, inverse);\n  }\n\n  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}","sourceCodeStart":285,"sourceCodeEnd":321,"githubUrl":"https://github.com/jestjs/jest/blob/8e6d128e4a278059ecddecaa97400b04c8ae5fd9/packages/expect/src/asymmetricMatchers.ts#L285-L321","documentation":"stringContaining / stringNotContaining build a StringContaining matcher whose constructor requires the sample to pass isA('String', sample). Anything that is not a string (number, object, undefined) throws an Error at construction time. This is a strict type guard so the substring `.includes()` call later is always valid.","triggerScenarios":"Calling `expect.stringContaining(value)` with a non-string value: a number, an object, a RegExp, or undefined. The error is thrown immediately when the matcher is constructed (before any assertion runs).","commonSituations":"Passing a RegExp where a substring was intended (use stringMatching for regex); passing a number that should have been a string; passing undefined from an optional field without a default.","solutions":["Pass a plain string substring: `expect.stringContaining('hello')`.","If you want regex matching, use `expect.stringMatching(/pattern/)` instead.","Coerce or default the input: `expect.stringContaining(String(value ?? ''))` when the source may be missing."],"exampleFix":"// before\nexpect(msg).toEqual(expect.stringContaining(/hello/)); // RegExp, not a string\n\n// after\nexpect(msg).toEqual(expect.stringContaining('hello'));\n// or for regex:\nexpect(msg).toEqual(expect.stringMatching(/hello/));","handlingStrategy":"type-guard","validationCode":"function stringContainingSafe(sample) {\n  if (typeof sample !== 'string') {\n    throw new TypeError('stringContaining requires a string');\n  }\n  return expect.stringContaining(sample);\n}","typeGuard":"function isString(v: unknown): v is string {\n  return typeof v === 'string';\n}\n\nconst m = isString(sample) ? expect.stringContaining(sample) : expect.anything();","tryCatchPattern":null,"preventionTips":["Use stringContaining for literal substrings and stringMatching for regex.","Coerce uncertain inputs with String(...) when a string pattern is intended.","Default optional substring samples to '' rather than undefined."],"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"}