Trek_CN/server/tests/unit/nest/maps.service.test.ts
2026-07-11 15:48:47 +08:00

130 lines
5.1 KiB
TypeScript

import { describe, it, expect, vi, beforeEach } from 'vitest';
const { amapPlaces } = vi.hoisted(() => ({
amapPlaces: {
searchAmapPlaces: vi.fn(),
autocompleteAmapPlaces: vi.fn(),
getAmapPlaceDetails: vi.fn(),
getAmapPlaceDetailsExpanded: vi.fn(),
reverseAmapGeocode: vi.fn(),
searchAmapPois: vi.fn(),
resolveAmapUri: vi.fn(),
},
}));
vi.mock('../../../src/services/amap/amap.places', () => amapPlaces);
const { serveFilePath } = vi.hoisted(() => ({ serveFilePath: vi.fn() }));
vi.mock('../../../src/services/placePhotoCache', () => ({ serveFilePath }));
import { MapsService } from '../../../src/nest/maps/maps.service';
import type { DatabaseService } from '../../../src/nest/database/database.service';
/** A DatabaseService stub whose get() returns the row the test wants. */
function makeDb(row?: { value: string }) {
const get = vi.fn(() => row);
const db = { get } as unknown as DatabaseService;
return { db, get };
}
function svc(row?: { value: string }) {
return new MapsService(makeDb(row).db);
}
beforeEach(() => vi.clearAllMocks());
describe('MapsService', () => {
describe('kill-switch settings reads', () => {
it('reports a switch disabled when the stored value is exactly "false"', () => {
expect(svc({ value: 'false' }).autocompleteDisabled()).toBe(true);
expect(svc({ value: 'false' }).detailsDisabled()).toBe(true);
expect(svc({ value: 'false' }).photosDisabled()).toBe(true);
});
it('reports enabled when the value is "true"', () => {
expect(svc({ value: 'true' }).autocompleteDisabled()).toBe(false);
expect(svc({ value: 'true' }).detailsDisabled()).toBe(false);
expect(svc({ value: 'true' }).photosDisabled()).toBe(false);
});
it('reports enabled when the setting row is absent', () => {
expect(svc(undefined).autocompleteDisabled()).toBe(false);
expect(svc(undefined).detailsDisabled()).toBe(false);
expect(svc(undefined).photosDisabled()).toBe(false);
});
it('queries the matching app_settings key', () => {
const { db, get } = makeDb({ value: 'true' });
const s = new MapsService(db);
s.autocompleteDisabled();
expect(get).toHaveBeenCalledWith(expect.stringContaining('app_settings'), 'places_autocomplete_enabled');
s.detailsDisabled();
expect(get).toHaveBeenCalledWith(expect.any(String), 'places_details_enabled');
s.photosDisabled();
expect(get).toHaveBeenCalledWith(expect.any(String), 'places_photos_enabled');
});
});
describe('delegation to the AMap adapter', () => {
it('search forwards userId, query, lang and bias', () => {
amapPlaces.searchAmapPlaces.mockResolvedValue({ places: [], source: 'amap' });
const bias = { lat: 1, lng: 2, radius: 5 };
svc().search(3, 'berlin', 'de', bias);
expect(amapPlaces.searchAmapPlaces).toHaveBeenCalledWith(expect.anything(), 'berlin', 'de', bias);
});
it('search works without optional args', () => {
svc().search(3, 'berlin');
expect(amapPlaces.searchAmapPlaces).toHaveBeenCalledWith(expect.anything(), 'berlin', undefined, undefined);
});
it('autocomplete forwards through', () => {
const bias = { low: { lat: 1, lng: 2 }, high: { lat: 3, lng: 4 } };
svc().autocomplete(3, 'be', 'en', bias);
expect(amapPlaces.autocompleteAmapPlaces).toHaveBeenCalledWith(expect.anything(), 'be', 'en', bias);
});
it('details forwards through', () => {
svc().details(3, 'p1', 'de');
expect(amapPlaces.getAmapPlaceDetails).toHaveBeenCalledWith(expect.anything(), 'p1', 'de');
});
it('detailsExpanded forwards refresh through', () => {
svc().detailsExpanded(3, 'p1', 'de', true);
expect(amapPlaces.getAmapPlaceDetailsExpanded).toHaveBeenCalledWith(expect.anything(), 'p1', 'de', true);
});
it('photo returns an empty AMap-compatible result without calling legacy providers', async () => {
await expect(svc().photo(3, 'p1', 1.5, 2.5, 'Spot')).resolves.toEqual({ photoUrl: null });
});
it('reverse forwards through', () => {
svc().reverse('1', '2', 'de');
expect(amapPlaces.reverseAmapGeocode).toHaveBeenCalledWith(expect.anything(), '1', '2', 'de');
});
it('resolveUrl forwards through', () => {
svc().resolveUrl('https://uri.amap.com/marker?position=116.39747,39.908823');
expect(amapPlaces.resolveAmapUri).toHaveBeenCalledWith('https://uri.amap.com/marker?position=116.39747,39.908823');
});
it('pois forwards category and bbox through', () => {
const bbox = { south: 1, west: 2, north: 3, east: 4 };
svc().pois('cafe', bbox);
expect(amapPlaces.searchAmapPois).toHaveBeenCalledWith(expect.anything(), 'cafe', bbox);
});
});
describe('photoBytesPath', () => {
it('returns the cached file path from placePhotoCache', () => {
serveFilePath.mockReturnValue('/cache/p1.jpg');
expect(svc().photoBytesPath('p1')).toBe('/cache/p1.jpg');
expect(serveFilePath).toHaveBeenCalledWith('p1');
});
it('returns null when nothing is cached', () => {
serveFilePath.mockReturnValue(null);
expect(svc().photoBytesPath('p1')).toBeNull();
});
});
});