mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-21 22:46:32 +00:00
test(maps): the overpass place names cases get a suite of their own, the service suite back under its size
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
"tests/unit/nest/budget.service.db.test.ts": 2220,
|
||||
"tests/unit/nest/doc-sync/doc-sync.service.test.ts": 2511,
|
||||
"tests/unit/nest/journey-domain.service.test.ts": 3876,
|
||||
"tests/unit/nest/maps.service.test.ts": 3751,
|
||||
"tests/unit/nest/maps.service.test.ts": 3681,
|
||||
"tests/unit/nest/places.service.test.ts": 2561,
|
||||
"tests/unit/nest/trips.service.test.ts": 2404
|
||||
}
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* The names a search of OpenStreetMap places shows (#1655): the language of the
|
||||
* traveller before the native name, places closed for good left out, and an
|
||||
* unnamed e-bike charging point kept where nothing else unnamed is (BIK-07).
|
||||
* Moved out of maps.service.test.ts as they were, under the describe name they
|
||||
* had there.
|
||||
*/
|
||||
import { OsmClient } from '../../../src/nest/maps/providers/osm.client';
|
||||
|
||||
import { describe, it, expect, vi, afterEach } from 'vitest';
|
||||
|
||||
const osm = new OsmClient();
|
||||
|
||||
afterEach(() => {
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
|
||||
describe('searchOverpassPois localized names (#1655)', () => {
|
||||
// Elephant and Obelisk in Rome: OSM ships the native name plus localized tags.
|
||||
const tags = {
|
||||
name: 'Obelisco della Minerva',
|
||||
'name:en': 'Elephant and Obelisk',
|
||||
'name:de': 'Minerva-Obelisk',
|
||||
int_name: 'Elephant Obelisk',
|
||||
tourism: 'attraction',
|
||||
};
|
||||
const stubOverpass = (elementTags: Record<string, string>) =>
|
||||
vi.stubGlobal(
|
||||
'fetch',
|
||||
vi.fn().mockResolvedValue({
|
||||
ok: true,
|
||||
json: async () => ({ elements: [{ type: 'node', id: 1, lat: 41.9, lon: 12.48, tags: elementTags }] }),
|
||||
}),
|
||||
);
|
||||
// Distinct bboxes per case so the module-level POI_CACHE (keyed by lang+bbox)
|
||||
// never serves one case's names to another.
|
||||
const bbox = (n: number) => ({ south: 41 + n / 100, west: 12, north: 42 + n / 100, east: 13 });
|
||||
|
||||
it('prefers name:<lang> for the user language over the native name', async () => {
|
||||
stubOverpass(tags);
|
||||
const { pois } = await osm.searchOverpassPois('sights', bbox(1), 'en-US');
|
||||
expect(pois[0].name).toBe('Elephant and Obelisk');
|
||||
});
|
||||
|
||||
it('localizes to a non-English language too', async () => {
|
||||
stubOverpass(tags);
|
||||
const { pois } = await osm.searchOverpassPois('sights', bbox(2), 'de-DE');
|
||||
expect(pois[0].name).toBe('Minerva-Obelisk');
|
||||
});
|
||||
|
||||
it('falls back to int_name when the language tag is absent', async () => {
|
||||
stubOverpass({ name: tags.name, int_name: tags.int_name, tourism: 'attraction' });
|
||||
const { pois } = await osm.searchOverpassPois('sights', bbox(3), 'fr-FR');
|
||||
expect(pois[0].name).toBe('Elephant Obelisk');
|
||||
});
|
||||
|
||||
it('skips POIs tagged as closed for good (#1341)', async () => {
|
||||
vi.stubGlobal(
|
||||
'fetch',
|
||||
vi.fn().mockResolvedValue({
|
||||
ok: true,
|
||||
json: async () => ({
|
||||
elements: [
|
||||
{
|
||||
type: 'node',
|
||||
id: 1,
|
||||
lat: 41.9,
|
||||
lon: 12.48,
|
||||
tags: { name: 'Gone Forever', tourism: 'attraction', disused: 'yes' },
|
||||
},
|
||||
{
|
||||
type: 'node',
|
||||
id: 2,
|
||||
lat: 41.9,
|
||||
lon: 12.49,
|
||||
tags: { name: 'Ruin', tourism: 'attraction', abandoned: 'yes' },
|
||||
},
|
||||
{
|
||||
type: 'node',
|
||||
id: 3,
|
||||
lat: 41.9,
|
||||
lon: 12.5,
|
||||
tags: { name: 'Shut', tourism: 'attraction', opening_hours: 'closed' },
|
||||
},
|
||||
{ type: 'node', id: 4, lat: 41.9, lon: 12.51, tags: { name: 'Open For Business', tourism: 'attraction' } },
|
||||
],
|
||||
}),
|
||||
}),
|
||||
);
|
||||
const { pois } = await osm.searchOverpassPois('sights', bbox(5), 'en-US');
|
||||
expect(pois.map((p) => p.name)).toEqual(['Open For Business']);
|
||||
});
|
||||
|
||||
it('falls back to the native name when no localized tag exists', async () => {
|
||||
stubOverpass({ name: tags.name, tourism: 'attraction' });
|
||||
const { pois } = await osm.searchOverpassPois('sights', bbox(4), 'fr-FR');
|
||||
expect(pois[0].name).toBe('Obelisco della Minerva');
|
||||
});
|
||||
|
||||
it('keeps an unnamed e-bike charging point, as the search along a tour does (BIK-07)', async () => {
|
||||
stubOverpass({ amenity: 'charging_station', bicycle: 'yes', 'socket:schuko': '2' });
|
||||
const { pois } = await osm.searchOverpassPois('ebike_charging', bbox(6), 'en-US');
|
||||
expect(pois.map((p) => [p.name, p.category])).toEqual([['', 'ebike_charging']]);
|
||||
});
|
||||
|
||||
it('still drops an unnamed place of any other kind', async () => {
|
||||
stubOverpass({ tourism: 'attraction' });
|
||||
const { pois } = await osm.searchOverpassPois('sights', bbox(7), 'en-US');
|
||||
expect(pois).toEqual([]);
|
||||
});
|
||||
});
|
||||
@@ -1009,85 +1009,6 @@ describe('fetchOverpassDetails (fetch stubbed)', () => {
|
||||
});
|
||||
});
|
||||
|
||||
// ── searchOverpassPois localized names (#1655) ───────────────────────────────
|
||||
|
||||
describe('searchOverpassPois localized names (#1655)', () => {
|
||||
// Elephant and Obelisk in Rome: OSM ships the native name plus localized tags.
|
||||
const tags = {
|
||||
name: 'Obelisco della Minerva',
|
||||
'name:en': 'Elephant and Obelisk',
|
||||
'name:de': 'Minerva-Obelisk',
|
||||
int_name: 'Elephant Obelisk',
|
||||
tourism: 'attraction',
|
||||
};
|
||||
const stubOverpass = (elementTags: Record<string, string>) =>
|
||||
vi.stubGlobal(
|
||||
'fetch',
|
||||
vi.fn().mockResolvedValue({
|
||||
ok: true,
|
||||
json: async () => ({ elements: [{ type: 'node', id: 1, lat: 41.9, lon: 12.48, tags: elementTags }] }),
|
||||
}),
|
||||
);
|
||||
// Distinct bboxes per case so the module-level POI_CACHE (keyed by lang+bbox)
|
||||
// never serves one case's names to another.
|
||||
const bbox = (n: number) => ({ south: 41 + n / 100, west: 12, north: 42 + n / 100, east: 13 });
|
||||
|
||||
it('prefers name:<lang> for the user language over the native name', async () => {
|
||||
stubOverpass(tags);
|
||||
const { pois } = await osm.searchOverpassPois('sights', bbox(1), 'en-US');
|
||||
expect(pois[0].name).toBe('Elephant and Obelisk');
|
||||
});
|
||||
|
||||
it('localizes to a non-English language too', async () => {
|
||||
stubOverpass(tags);
|
||||
const { pois } = await osm.searchOverpassPois('sights', bbox(2), 'de-DE');
|
||||
expect(pois[0].name).toBe('Minerva-Obelisk');
|
||||
});
|
||||
|
||||
it('falls back to int_name when the language tag is absent', async () => {
|
||||
stubOverpass({ name: tags.name, int_name: tags.int_name, tourism: 'attraction' });
|
||||
const { pois } = await osm.searchOverpassPois('sights', bbox(3), 'fr-FR');
|
||||
expect(pois[0].name).toBe('Elephant Obelisk');
|
||||
});
|
||||
|
||||
it('skips POIs tagged as closed for good (#1341)', async () => {
|
||||
vi.stubGlobal(
|
||||
'fetch',
|
||||
vi.fn().mockResolvedValue({
|
||||
ok: true,
|
||||
json: async () => ({
|
||||
elements: [
|
||||
{ type: 'node', id: 1, lat: 41.9, lon: 12.48, tags: { name: 'Gone Forever', tourism: 'attraction', disused: 'yes' } },
|
||||
{ type: 'node', id: 2, lat: 41.9, lon: 12.49, tags: { name: 'Ruin', tourism: 'attraction', abandoned: 'yes' } },
|
||||
{ type: 'node', id: 3, lat: 41.9, lon: 12.5, tags: { name: 'Shut', tourism: 'attraction', opening_hours: 'closed' } },
|
||||
{ type: 'node', id: 4, lat: 41.9, lon: 12.51, tags: { name: 'Open For Business', tourism: 'attraction' } },
|
||||
],
|
||||
}),
|
||||
}),
|
||||
);
|
||||
const { pois } = await osm.searchOverpassPois('sights', bbox(5), 'en-US');
|
||||
expect(pois.map((p: any) => p.name)).toEqual(['Open For Business']);
|
||||
});
|
||||
|
||||
it('falls back to the native name when no localized tag exists', async () => {
|
||||
stubOverpass({ name: tags.name, tourism: 'attraction' });
|
||||
const { pois } = await osm.searchOverpassPois('sights', bbox(4), 'fr-FR');
|
||||
expect(pois[0].name).toBe('Obelisco della Minerva');
|
||||
});
|
||||
|
||||
it('keeps an unnamed e-bike charging point, as the search along a tour does (BIK-07)', async () => {
|
||||
stubOverpass({ amenity: 'charging_station', bicycle: 'yes', 'socket:schuko': '2' });
|
||||
const { pois } = await osm.searchOverpassPois('ebike_charging', bbox(6), 'en-US');
|
||||
expect(pois.map((p: any) => [p.name, p.category])).toEqual([['', 'ebike_charging']]);
|
||||
});
|
||||
|
||||
it('still drops an unnamed place of any other kind', async () => {
|
||||
stubOverpass({ tourism: 'attraction' });
|
||||
const { pois } = await osm.searchOverpassPois('sights', bbox(7), 'en-US');
|
||||
expect(pois).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
// ── fetchWikimediaPhoto (fetch stubbed) ───────────────────────────────────────
|
||||
|
||||
describe('fetchWikimediaPhoto (fetch stubbed)', () => {
|
||||
|
||||
Reference in New Issue
Block a user