From 7f23ab825b7d46ba7f7001324210dd66d940f46f Mon Sep 17 00:00:00 2001 From: webtecnica Date: Tue, 29 Sep 2026 14:17:57 -0300 Subject: [PATCH] =?UTF-8?q?fix(inbox):=20o=20piso=20da=20busca=20tira=20o?= =?UTF-8?q?=20asterisco=20=E2=80=94=20'**'=20deixa=20de=20devolver=20a=20l?= =?UTF-8?q?ista=20inteira=20(#1935)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ao-volta-a-lista-inteira-pelo-asterisco.md | 10 +++++++ lib/inbox/termo-de-busca.ts | 12 ++++++-- .../termo-de-busca-tolera-digitacao.test.ts | 29 +++++++++++++++++++ 3 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 .changes/busca-nao-volta-a-lista-inteira-pelo-asterisco.md diff --git a/.changes/busca-nao-volta-a-lista-inteira-pelo-asterisco.md b/.changes/busca-nao-volta-a-lista-inteira-pelo-asterisco.md new file mode 100644 index 000000000..20e891341 --- /dev/null +++ b/.changes/busca-nao-volta-a-lista-inteira-pelo-asterisco.md @@ -0,0 +1,10 @@ +--- +impacto: nada_mudou +secao: corrigido +titulo: A busca deixa de devolver a lista inteira quando o termo tem só asteriscos +--- + +Digitar um termo feito só de asteriscos (duplo estrela, `* *` sem espaços) na busca da caixa de +entrada ou de contatos podia devolver tudo: o asterisco não era tratado como separador e virava +curinga no `or=`, equivalente a buscar sem critério. Agora o piso da busca o ignora — um termo só +de asteriscos não vai ao banco. \ No newline at end of file diff --git a/lib/inbox/termo-de-busca.ts b/lib/inbox/termo-de-busca.ts index e86714dfb..e5bff1942 100644 --- a/lib/inbox/termo-de-busca.ts +++ b/lib/inbox/termo-de-busca.ts @@ -80,8 +80,16 @@ export function normalizarTermoDeBusca(bruto: string): string { * O `replace` NO PISO não muda o termo que vai ao banco — ele só decide se vale * consultar. O parêntese que sobra (ex. um telefone `(15) 99259-4261`) continua * vindo atrás dele e segue funcionando, como os controles abaixo provam. + * + * O ASTERISCO entra aqui pela mesma porta do parêntese (#1935): a pessoa pode + * digitar `*` (por exemplo `s*` pensando em curinga de nome). `normalizarTermoDeBusca` + * não colapsa `*` (não é separador), então `"**"` passa o piso; e `termoSeguroParaOr` + * NÃO escapa `*` — no `or=` do PostgREST, `*` vira `%`, e `**` vira `%%`: a lista + * inteira de volta, o mesmo defeito que o piso veio consertar. Tirá-lo do piso é + * seguro porque um `*` SEM homem no termo não significa nada para a busca — ele + * só ia ao banco para virar curinga e casar tudo. */ export function buscaValeConsulta(bruto: string): boolean { - const semParenteses = bruto.replace(/[()]/g, " "); - return normalizarTermoDeBusca(semParenteses).length >= PISO_DA_BUSCA; + const semLixo = bruto.replace(/[()*]/g, " "); + return normalizarTermoDeBusca(semLixo).length >= PISO_DA_BUSCA; } diff --git a/tests/unit/termo-de-busca-tolera-digitacao.test.ts b/tests/unit/termo-de-busca-tolera-digitacao.test.ts index 0d2d571c6..a8eee9163 100644 --- a/tests/unit/termo-de-busca-tolera-digitacao.test.ts +++ b/tests/unit/termo-de-busca-tolera-digitacao.test.ts @@ -130,3 +130,32 @@ describe("termo de busca não devolve a lista inteira pelo parêntese (#1895)", expect(buscaValeConsulta("(15) 99259")).toBe(true); }); }); + +/** + * O asterisco (#1935): a lista inteira de volta por quem digita curinga. + * + * Medido na main: `buscaValeConsulta("**") === true` porque `normalizarTermoDeBusca` + * não colapsa `*` (não é separador), então `"**"` vira 2 caracteres e passa o piso; + * `termoSeguroParaOr` NÃO escapa `*`, e no `or=` do PostgREST `*` vira `%` — `**` + * casa quase tudo. É o mesmo defeito do parêntese, pela porta do usuário que digita + * `*` pensando em curinga. + * + * A régua tira o `*` ANTES de medir o piso, junto do parêntese. Se alguém remover + * o `*` do `replace`, estes casos ficam VERMELHOS (a sabotagem da #1935 prevê isso). + */ +describe("termo de busca não devolve a lista inteira pelo asterisco (#1935)", () => { + it("'**' NÃO vale consulta", () => { + expect(buscaValeConsulta("**")).toBe(false); + }); + + it("asterisco com conteúdo mínimo por baixo não vale", () => { + expect(buscaValeConsulta("s*")).toBe(false); + expect(buscaValeConsulta("*")).toBe(false); + }); + + it("CONTROLE: nome com conteúdo real continua valendo", () => { + // Sem estes, uma implementação que recusasse qualquer termo passaria. + expect(buscaValeConsulta("sabrina")).toBe(true); + expect(buscaValeConsulta("paulo jr")).toBe(true); + }); +});