{"id":"05333d42011db35f","repo":"vitest-dev/vitest","slug":"locator-filter-expects-at-least-one-filter-none-p","errorCode":null,"errorMessage":"Locator.filter expects at least one filter. None provided.","messagePattern":"Locator\\.filter expects at least one filter\\. None provided\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/browser/src/client/tester/locators.ts","lineNumber":298,"sourceCode":"      selectors.push(`internal:has-text=${escapeForTextSelector(filter.hasText, false)}`)\n    }\n\n    if (filter?.hasNotText) {\n      selectors.push(`internal:has-not-text=${escapeForTextSelector(filter.hasNotText, false)}`)\n    }\n\n    if (filter?.has) {\n      const locator = filter.has as Locator\n      selectors.push(`internal:has=${JSON.stringify(locator._pwSelector || locator.selector)}`)\n    }\n\n    if (filter?.hasNot) {\n      const locator = filter.hasNot as Locator\n      selectors.push(`internal:has-not=${JSON.stringify(locator._pwSelector || locator.selector)}`)\n    }\n\n    if (!selectors.length) {\n      throw new Error(`Locator.filter expects at least one filter. None provided.`)\n    }\n\n    return this.locator(selectors.join(' >> '))\n  }\n\n  public and(locator: Locator): Locator {\n    return this.locator(`internal:and=${JSON.stringify(locator._pwSelector || locator.selector)}`)\n  }\n\n  public or(locator: Locator): Locator {\n    return this.locator(`internal:or=${JSON.stringify(locator._pwSelector || locator.selector)}`)\n  }\n\n  public query(): HTMLElement | SVGElement | null {\n    const parsedSelector = this._parsedSelector || (this._parsedSelector = selectorEngine.parseSelector(this._pwSelector || this.selector))\n    return selectorEngine.querySelector(parsedSelector, document.documentElement, true) as HTMLElement | SVGElement\n  }\n","sourceCodeStart":280,"sourceCodeEnd":316,"githubUrl":"https://github.com/vitest-dev/vitest/blob/d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09/packages/browser/src/client/tester/locators.ts#L280-L316","documentation":"Thrown by `Locator.filter` at locators.ts:297-298 when none of the supported filter keys (`hasText`, `hasNotText`, `has`, `hasNot`) are present on the options object. Calling `.filter()` with no constraints is meaningless and would just rebuild the same locator, so Vitest requires at least one.","triggerScenarios":"`page.locator('div').filter({})`, `.filter()` with an object containing only unknown keys, or `.filter({ level: 2 })`. Also when destructuring options that turn out undefined: `.filter({ hasText: maybeUndefined })`.","commonSituations":"Building filter options dynamically and ending up with all-undefined values. Copy-paste from another locator that dropped the relevant key. Misremembering the supported filter keys.","solutions":["Provide at least one of `hasText`, `hasNotText`, `has`, or `hasNot`: `locator.filter({ hasText: 'Save' })`.","When building filters conditionally, only call `.filter()` if at least one key is truthy.","Double-check key names against the `LocatorOptions` type (e.g. it's `hasText`, not `text`)."],"exampleFix":"// before\nconst opts = condition ? { hasText: 'x' } : {}\nlocator.filter(opts)\n\n// after\nconst opts = condition ? { hasText: 'x' } : null\nif (opts) locator.filter(opts)","handlingStrategy":"validation","validationCode":"type FilterOptions = { hasText?: unknown; hasNotText?: unknown; has?: unknown; hasNot?: unknown }\nfunction hasAnyFilter(o: Partial<FilterOptions>): boolean {\n  return !!(o.hasText ?? o.hasNotText ?? o.has ?? o.hasNot)\n}\nif (!hasAnyFilter(opts)) throw new Error('provide at least one filter')","typeGuard":"function hasFilterKey(o: unknown): o is { hasText?: unknown; hasNotText?: unknown; has?: unknown; hasNot?: unknown } {\n  return !!o && typeof o === 'object' && ('hasText' in o || 'hasNotText' in o || 'has' in o || 'hasNot' in o)\n}","tryCatchPattern":null,"preventionTips":["Always supply at least one of hasText/hasNotText/has/hasNot to .filter().","Build filter objects conditionally and skip .filter() when empty.","Remember the correct key names; level/text-only keys are ignored."],"tags":["browser","locator","api-misuse","argument-validation"],"analyzedSha":"d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09","analyzedAt":"2026-08-03T20:23:56.861Z","schemaVersion":2}