From 773e4426eb9e3c8d325a2615502fb2a49427ba51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Ign=C3=A1cio=20Fontoura=20Solla?= Date: Thu, 30 Jul 2026 22:28:50 -0300 Subject: [PATCH] =?UTF-8?q?fix(test):=20queries=20distintas=20em=20specs?= =?UTF-8?q?=20de=20portfolio=20de=20munic=C3=ADpio?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nova Soure vs Nova Canaã compartilham o primeiro token; distinctWordStartQuery escolhe palavra que casa só com o alvo e evita falso positivo no assessor. --- tests/helpers/distinctWordStartQuery.ts | 27 +++++++++++++++++++ .../int/homeSearchMunicipalities.int.spec.ts | 5 ++-- .../searchStaffMunicipalityHits.int.spec.ts | 5 ++-- .../unit/distinctWordStartQuery.unit.spec.ts | 14 ++++++++++ 4 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 tests/helpers/distinctWordStartQuery.ts create mode 100644 tests/unit/distinctWordStartQuery.unit.spec.ts diff --git a/tests/helpers/distinctWordStartQuery.ts b/tests/helpers/distinctWordStartQuery.ts new file mode 100644 index 00000000..984eab40 --- /dev/null +++ b/tests/helpers/distinctWordStartQuery.ts @@ -0,0 +1,27 @@ +import { homeSearchQueryIsActive } from '@/lib/campaignHomeSearchContract' +import { normalizeHomeSearchName } from '@/lib/homeSearchMunicipalityMatch' +import { matchesNormalizedAtWordStart } from '@/lib/wordStartFilter' + +/** + * Picks a word-start query that matches `targetName` but not `excludeName`. + * Portfolio scoping specs allocate two municipalities per test; sharing the + * first token (e.g. Nova Soure vs Nova Canaã) makes advisor assertions flaky. + */ +export function distinctWordStartQuery(targetName: string, excludeName: string): string { + const normalizedTarget = normalizeHomeSearchName(targetName) + const normalizedExclude = normalizeHomeSearchName(excludeName) + + for (const word of targetName.split(/\s+/)) { + const query = word.trim() + if (!homeSearchQueryIsActive(normalizeHomeSearchName(query))) continue + const normalizedQuery = normalizeHomeSearchName(query) + if ( + matchesNormalizedAtWordStart(normalizedTarget, normalizedQuery) && + !matchesNormalizedAtWordStart(normalizedExclude, normalizedQuery) + ) { + return query + } + } + + throw new Error(`No word-start query matches "${targetName}" without matching "${excludeName}"`) +} diff --git a/tests/int/homeSearchMunicipalities.int.spec.ts b/tests/int/homeSearchMunicipalities.int.spec.ts index 77cd69b5..cbbbb447 100644 --- a/tests/int/homeSearchMunicipalities.int.spec.ts +++ b/tests/int/homeSearchMunicipalities.int.spec.ts @@ -9,6 +9,7 @@ import config from '@/payload.config' import { searchHomeMunicipalities } from '@/utilities/homeSearch/searchHomeMunicipalities' import { installCampaignFixtures } from '../helpers/campaignFixtures' +import { distinctWordStartQuery } from '../helpers/distinctWordStartQuery' let payload: Payload const campaignFixtures = installCampaignFixtures({ @@ -51,8 +52,8 @@ describe('searchHomeMunicipalities (B48)', () => { const other = await fixtures.getMunicipality() await fixtures.assignMunicipalityAdvisors(administered.id, [advisor.id]) - const otherQuery = other.name.split(/\s+/)[0]! - const administeredQuery = administered.name.split(/\s+/)[0]! + const otherQuery = distinctWordStartQuery(other.name, administered.name) + const administeredQuery = distinctWordStartQuery(administered.name, other.name) const advisorResult = await searchHomeMunicipalities(payload, advisor, otherQuery) expect(advisorResult.municipalities.map((hit) => hit.slug)).toEqual([]) diff --git a/tests/int/searchStaffMunicipalityHits.int.spec.ts b/tests/int/searchStaffMunicipalityHits.int.spec.ts index 9e12e7dc..7a6fcc20 100644 --- a/tests/int/searchStaffMunicipalityHits.int.spec.ts +++ b/tests/int/searchStaffMunicipalityHits.int.spec.ts @@ -9,6 +9,7 @@ import config from '@/payload.config' import { searchStaffMunicipalityHits } from '@/utilities/homeSearch/searchStaffMunicipalityHits' import { installCampaignFixtures } from '../helpers/campaignFixtures' +import { distinctWordStartQuery } from '../helpers/distinctWordStartQuery' let payload: Payload const campaignFixtures = installCampaignFixtures({ @@ -50,8 +51,8 @@ describe('searchStaffMunicipalityHits (B60)', () => { const other = await fixtures.getMunicipality() await fixtures.assignMunicipalityAdvisors(administered.id, [advisor.id]) - const otherQuery = other.name.split(/\s+/)[0]! - const administeredQuery = administered.name.split(/\s+/)[0]! + const otherQuery = distinctWordStartQuery(other.name, administered.name) + const administeredQuery = distinctWordStartQuery(administered.name, other.name) const advisorResult = await searchStaffMunicipalityHits(payload, advisor, otherQuery) expect(advisorResult.map((hit) => hit.slug)).toEqual([]) diff --git a/tests/unit/distinctWordStartQuery.unit.spec.ts b/tests/unit/distinctWordStartQuery.unit.spec.ts new file mode 100644 index 00000000..d90b6450 --- /dev/null +++ b/tests/unit/distinctWordStartQuery.unit.spec.ts @@ -0,0 +1,14 @@ +import { describe, expect, it } from 'vitest' + +import { distinctWordStartQuery } from '../helpers/distinctWordStartQuery' + +describe('distinctWordStartQuery', () => { + it('returns a word that matches only the target name', () => { + expect(distinctWordStartQuery('Nova Canaã', 'Nova Soure')).toBe('Canaã') + expect(distinctWordStartQuery('Nova Soure', 'Nova Canaã')).toBe('Soure') + }) + + it('falls back to the first word when names do not share a prefix token', () => { + expect(distinctWordStartQuery('Cairu', 'Feira de Santana')).toBe('Cairu') + }) +})