Compare commits

...
Author SHA1 Message Date
Sonarly Claude Code 506fa18295 Autocomplete errors surface as address save failures
https://sonarly.com/issue/27228?type=bug

UTF-8 characters in address fields trigger unhandled Google Places autocomplete errors that surface in the UI, making users believe the address save was rejected when the actual persistence pipeline fully supports UTF-8.
2026-04-16 17:10:10 +00:00
3 changed files with 68 additions and 7 deletions
@@ -293,6 +293,42 @@ describe('useAddressAutocomplete', () => {
);
});
it('should close dropdown and not throw when autocomplete query fails', async () => {
mockGetPlaceAutocompleteData.mockRejectedValue(
new Error('Network error'),
);
const { result } = renderHook(() => useAddressAutocomplete());
await act(async () => {
await result.current.getAutocompletePlaceData('ü', 'token123');
});
expect(mockCloseDropdown).toHaveBeenCalled();
expect(mockOpenDropdown).not.toHaveBeenCalled();
});
it('should close dropdown and not throw when place details query fails', async () => {
const mockOnChange = jest.fn();
mockGetPlaceDetailsData.mockRejectedValue(
new Error('Network error'),
);
const { result } = renderHook(() => useAddressAutocomplete(mockOnChange));
await act(async () => {
await result.current.autoFillInputsFromPlaceDetails(
'place123',
'token123',
'123 Main St',
);
});
expect(mockCloseDropdown).toHaveBeenCalled();
expect(mockOnChange).not.toHaveBeenCalled();
});
it('should handle address autocomplete with country and isFieldCity parameters', async () => {
mockGetPlaceAutocompleteData.mockResolvedValue([
{ text: 'Boston, MA', placeId: 'place1' },
@@ -47,12 +47,20 @@ export const useAddressAutocomplete = (
country?: string,
isFieldCity?: boolean,
) => {
const placeAutocompleteData = await getPlaceAutocompleteData(
address,
token,
country,
isFieldCity,
);
let placeAutocompleteData: PlaceAutocompleteResult[] | undefined;
try {
placeAutocompleteData = await getPlaceAutocompleteData(
address,
token,
country,
isFieldCity,
);
} catch {
closeDropdownOfAutocomplete();
return;
}
const newData = placeAutocompleteData?.map((data) => ({
text: data.text,
@@ -76,7 +84,16 @@ export const useAddressAutocomplete = (
addressStreet1?: string,
internalValue?: FieldAddressDraftValue,
) => {
const placeData = await getPlaceDetailsData(placeId, token);
let placeData: Awaited<ReturnType<typeof getPlaceDetailsData>>;
try {
placeData = await getPlaceDetailsData(placeId, token);
} catch {
closeDropdownOfAutocomplete();
return;
}
const countryName = findCountryNameByCountryCode(placeData?.country);
const updatedAddress = {
@@ -34,6 +34,10 @@ export class GeoMapService {
country?: string,
isFieldCity?: boolean,
): Promise<GeoMapAutocompleteSanitizedResult[] | undefined> {
if (!isNonEmptyString(this.apiMapKey)) {
return [];
}
if (!isNonEmptyString(address?.trim())) {
return [];
}
@@ -61,6 +65,10 @@ export class GeoMapService {
placeId: string,
token: string,
): Promise<GeoMapAddressFields | undefined> {
if (!isNonEmptyString(this.apiMapKey)) {
return {};
}
const httpClient = this.secureHttpClientService.getHttpClient();
const result = await httpClient.get(