import { describe, it, expect, vi, beforeEach } from 'vitest' import { useAddressAutocomplete, AddressAutocompleteUnavailableError, } from '../useAddressAutocomplete' // On mocke le helper d'appel externe : aucun vrai appel reseau a la BAN. // vi.mock est hoiste par Vitest au-dessus des imports. const mockHttp = vi.hoisted(() => vi.fn()) vi.mock('~/shared/utils/httpExternal', () => ({ httpExternal: mockHttp })) const BAN_URL = 'https://api-adresse.data.gouv.fr/search/' describe('useAddressAutocomplete', () => { beforeEach(() => { mockHttp.mockReset() }) describe('searchCity', () => { it('interroge la BAN en type=municipality et mappe { city, postalCode }', async () => { mockHttp.mockResolvedValueOnce({ type: 'FeatureCollection', features: [ { properties: { city: 'Amiens', postcode: '80000', name: 'Amiens', type: 'municipality' } }, { properties: { city: 'Amiens', postcode: '80080', name: 'Amiens', type: 'municipality' } }, ], }) const { searchCity } = useAddressAutocomplete() const res = await searchCity('80000') expect(mockHttp).toHaveBeenCalledWith( BAN_URL, expect.objectContaining({ query: { q: '80000', type: 'municipality' } }), ) expect(res).toEqual([ { city: 'Amiens', postalCode: '80000' }, { city: 'Amiens', postalCode: '80080' }, ]) }) it('throw une AddressAutocompleteUnavailableError sur erreur reseau / 5xx', async () => { mockHttp.mockRejectedValueOnce(new Error('500 Server Error')) const { searchCity } = useAddressAutocomplete() await expect(searchCity('80000')).rejects.toBeInstanceOf(AddressAutocompleteUnavailableError) }) it('throw une AddressAutocompleteUnavailableError sur timeout', async () => { mockHttp.mockRejectedValueOnce(new Error('The operation was aborted due to timeout')) const { searchCity } = useAddressAutocomplete() await expect(searchCity('80000')).rejects.toBeInstanceOf(AddressAutocompleteUnavailableError) }) }) describe('searchAddress', () => { it('interroge la BAN avec postcode et mappe la suggestion', async () => { mockHttp.mockResolvedValueOnce({ type: 'FeatureCollection', features: [ { properties: { label: '8 Boulevard du Port 80000 Amiens', name: '8 Boulevard du Port', street: 'Boulevard du Port', postcode: '80000', city: 'Amiens', type: 'housenumber', }, }, ], }) const { searchAddress } = useAddressAutocomplete() const res = await searchAddress('8 boulevard du port', '80000') expect(mockHttp).toHaveBeenCalledWith( BAN_URL, expect.objectContaining({ query: { q: '8 boulevard du port', postcode: '80000' }, }), ) expect(res).toEqual([ { label: '8 Boulevard du Port 80000 Amiens', street: '8 Boulevard du Port', postalCode: '80000', city: 'Amiens', }, ]) }) it('omet le parametre postcode quand aucun code postal n\'est fourni', async () => { mockHttp.mockResolvedValueOnce({ type: 'FeatureCollection', features: [] }) const { searchAddress } = useAddressAutocomplete() await searchAddress('8 boulevard du port') expect(mockHttp).toHaveBeenCalledWith( BAN_URL, expect.objectContaining({ query: { q: '8 boulevard du port' }, }), ) }) it('ne restreint PAS la recherche a type=housenumber (sinon la BAN ne renvoie rien tant qu\'aucun numero n\'est saisi)', async () => { // Regression : avec `type=housenumber`, une saisie de nom de rue sans // numero (ex: « boulevard du port ») renvoie 0 resultat cote BAN. mockHttp.mockResolvedValueOnce({ type: 'FeatureCollection', features: [] }) const { searchAddress } = useAddressAutocomplete() await searchAddress('boulevard du port', '80000') const sentQuery = mockHttp.mock.calls[0]?.[1]?.query as Record expect(sentQuery.type).toBeUndefined() }) it('throw une AddressAutocompleteUnavailableError sur erreur reseau', async () => { mockHttp.mockRejectedValueOnce(new Error('network down')) const { searchAddress } = useAddressAutocomplete() await expect(searchAddress('8 boulevard du port', '80000')).rejects.toBeInstanceOf( AddressAutocompleteUnavailableError, ) }) }) })