diff --git a/.env b/.env
index 150dfdb4..b5420fe2 100644
--- a/.env
+++ b/.env
@@ -3,6 +3,4 @@ VITE_VALHALLA_URL=https://valhalla1.openstreetmap.de
VITE_NOMINATIM_URL=https://nominatim.openstreetmap.org
VITE_TILE_SERVER_URL="https://tile.openstreetmap.org/{z}/{x}/{y}.png"
VITE_CENTER_COORDS="52.51831,13.393707"
-
-# Possible values: auto, bicycle, pedestrian, car, truck, bus, motor_scooter, motorcycle
-VITE_DEFAULT_COSTING_MODEL=bicycle
+VITE_DEFAULT_COSTING_MODEL=bicycle
\ No newline at end of file
diff --git a/src/components/settings-panel/settings-panel.spec.tsx b/src/components/settings-panel/settings-panel.spec.tsx
index 2a6c1c88..5ab8ae45 100644
--- a/src/components/settings-panel/settings-panel.spec.tsx
+++ b/src/components/settings-panel/settings-panel.spec.tsx
@@ -158,10 +158,10 @@ describe('SettingsPanel', () => {
).toBeInTheDocument();
});
- it('should render Reset button', () => {
+ it('should render Reset button', async () => {
renderWithQueryClient();
expect(
- screen.getByRole('button', { name: /^Reset$/i })
+ await screen.findByRole('button', { name: /^Reset$/i })
).toBeInTheDocument();
});
diff --git a/src/utils/nominatim.spec.ts b/src/utils/nominatim.spec.ts
new file mode 100644
index 00000000..ad1c975f
--- /dev/null
+++ b/src/utils/nominatim.spec.ts
@@ -0,0 +1,66 @@
+import { describe, it, expect, beforeEach } from 'vitest';
+import { parseGeocodeResponse } from './nominatim';
+import type { NominationResponse } from '@/components/types';
+
+describe('parseGeocodeResponse', () => {
+ let counter = 0;
+
+ beforeEach(() => {
+ counter = 0;
+ });
+
+ const makeResult = (name: string, lat?: string, lon?: string) =>
+ ({
+ display_name: name,
+ lat: lat ?? `${++counter}.0000`,
+ lon: lon ?? `${++counter}.0000`,
+ osm_type: 'node',
+ osm_id: counter,
+ }) as unknown as NominationResponse;
+
+ it('returns all results when there are no duplicates', () => {
+ const results = [makeResult('Place A'), makeResult('Place B')];
+
+ const processed = parseGeocodeResponse(results);
+ expect(processed).toHaveLength(2);
+ expect(processed[0]!.title).toBe('Place A');
+ expect(processed[1]!.title).toBe('Place B');
+ });
+
+ it('removes entries that have identical coordinates and same name after diacritic normalization', () => {
+ const lat = `${++counter}.0000`;
+ const lon = `${++counter}.0000`;
+
+ const results = [
+ makeResult('Pláce C', lat, lon),
+ makeResult('Place C', lat, lon),
+ makeResult('PLÁCE C', lat, lon),
+ ];
+
+ const processed = parseGeocodeResponse(results);
+ expect(processed).toHaveLength(1);
+ expect(processed[0]!.title).toBe('Pláce C');
+ });
+
+ it('keeps entries that have the same name but genuinely different coordinates', () => {
+ const results = [
+ makeResult('Place D'),
+ makeResult('Place D'),
+ makeResult('Place D'),
+ ];
+
+ const processed = parseGeocodeResponse(results);
+ expect(processed).toHaveLength(3);
+ expect(processed[0]!.title).toBe('Place D');
+ expect(processed[1]!.title).toBe('Place D');
+ expect(processed[2]!.title).toBe('Place D');
+ });
+
+ it('handles a single non-array result without throwing', () => {
+ const result = makeResult('Place E');
+
+ const processed = parseGeocodeResponse(result);
+ expect(processed).toHaveLength(1);
+ expect(processed[0]!.title).toBe('Place E');
+ });
+});
diff --git a/src/utils/nominatim.ts b/src/utils/nominatim.ts
index 686c3ff5..30f4b5fa 100644
--- a/src/utils/nominatim.ts
+++ b/src/utils/nominatim.ts
@@ -31,6 +31,8 @@ export const parseGeocodeResponse = (
}
const processedResults = [];
+ const seenKeys = new Set();
+
for (const [index, result] of results.entries()) {
if (
'error' in result &&
@@ -48,6 +50,19 @@ export const parseGeocodeResponse = (
addressindex: index,
});
} else {
+ const normalizedTitle = result.display_name
+ .toLowerCase()
+ .normalize('NFD')
+ .replace(/[\u0300-\u036f]/g, '');
+ const dedupeKey = result.boundingbox
+ ? `${normalizedTitle}${result.boundingbox.join(',')}`
+ : `${normalizedTitle}${result.lat}${result.lon}`;
+
+ if (seenKeys.has(dedupeKey)) {
+ continue;
+ }
+ seenKeys.add(dedupeKey);
+
processedResults.push({
title:
result.display_name.length > 0