File size: 4,970 Bytes
1f5ea39
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import { describe, it, expect, vi, beforeEach } from 'vitest';

const { maps } = vi.hoisted(() => ({
  maps: {
    searchPlaces: vi.fn(),
    autocompletePlaces: vi.fn(),
    getPlaceDetails: vi.fn(),
    getPlaceDetailsExpanded: vi.fn(),
    getPlacePhoto: vi.fn(),
    reverseGeocode: vi.fn(),
    resolveGoogleMapsUrl: vi.fn(),
    searchOverpassPois: vi.fn(),
  },
}));
vi.mock('../../../src/services/mapsService', () => maps);

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 legacy maps service', () => {
    it('search forwards userId, query, lang and bias', () => {
      maps.searchPlaces.mockResolvedValue({ places: [], source: 'osm' });
      const bias = { lat: 1, lng: 2, radius: 5 };
      svc().search(3, 'berlin', 'de', bias);
      expect(maps.searchPlaces).toHaveBeenCalledWith(3, 'berlin', 'de', bias);
    });

    it('search works without optional args', () => {
      svc().search(3, 'berlin');
      expect(maps.searchPlaces).toHaveBeenCalledWith(3, '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(maps.autocompletePlaces).toHaveBeenCalledWith(3, 'be', 'en', bias);
    });

    it('details forwards through', () => {
      svc().details(3, 'p1', 'de');
      expect(maps.getPlaceDetails).toHaveBeenCalledWith(3, 'p1', 'de');
    });

    it('detailsExpanded forwards refresh through', () => {
      svc().detailsExpanded(3, 'p1', 'de', true);
      expect(maps.getPlaceDetailsExpanded).toHaveBeenCalledWith(3, 'p1', 'de', true);
    });

    it('photo forwards coords and name through', () => {
      svc().photo(3, 'p1', 1.5, 2.5, 'Spot');
      expect(maps.getPlacePhoto).toHaveBeenCalledWith(3, 'p1', 1.5, 2.5, 'Spot');
    });

    it('reverse forwards through', () => {
      svc().reverse('1', '2', 'de');
      expect(maps.reverseGeocode).toHaveBeenCalledWith('1', '2', 'de');
    });

    it('resolveUrl forwards through', () => {
      svc().resolveUrl('https://maps.app.goo.gl/x');
      expect(maps.resolveGoogleMapsUrl).toHaveBeenCalledWith('https://maps.app.goo.gl/x');
    });

    it('pois forwards category and bbox through', () => {
      const bbox = { south: 1, west: 2, north: 3, east: 4 };
      svc().pois('cafe', bbox);
      expect(maps.searchOverpassPois).toHaveBeenCalledWith('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();
    });
  });
});