import { describe, it, expect, vi, beforeEach } from 'vitest' vi.mock('leaflet', () => { const markerMock = { on: vi.fn().mockReturnThis(), addTo: vi.fn().mockReturnThis(), setLatLng: vi.fn().mockReturnThis(), remove: vi.fn().mockReturnThis(), } return { default: { marker: vi.fn(() => markerMock), Icon: class {}, }, marker: vi.fn(() => markerMock), Icon: class {}, } }) vi.mock('~/lib/LeafletCustomTypes', () => ({ HnHMaxZoom: 6, ImageIcon: class { constructor(_opts: Record) {} }, })) import { createMarker, type MarkerData, type MapViewRef } from '../Marker' function makeMarkerData(overrides: Partial = {}): MarkerData { return { id: 1, position: { x: 100, y: 200 }, name: 'Tower', image: 'gfx/terobjs/mm/tower', hidden: false, map: 1, ...overrides, } } function makeMapViewRef(): MapViewRef { return { map: { unproject: vi.fn(() => ({ lat: 0, lng: 0 })), } as unknown as import('leaflet').Map, mapid: 1, markerLayer: { removeLayer: vi.fn(), addLayer: vi.fn(), } as unknown as import('leaflet').LayerGroup, } } describe('createMarker', () => { beforeEach(() => { vi.clearAllMocks() }) it('creates a marker with correct properties', () => { const marker = createMarker(makeMarkerData()) expect(marker.id).toBe(1) expect(marker.name).toBe('Tower') expect(marker.position).toEqual({ x: 100, y: 200 }) expect(marker.image).toBe('gfx/terobjs/mm/tower') expect(marker.hidden).toBe(false) expect(marker.map).toBe(1) expect(marker.value).toBe(1) expect(marker.text).toBe('Tower') }) it('detects quest type', () => { const marker = createMarker(makeMarkerData({ image: 'gfx/invobjs/small/bush' })) expect(marker.type).toBe('quest') }) it('detects quest type for bumling', () => { const marker = createMarker(makeMarkerData({ image: 'gfx/invobjs/small/bumling' })) expect(marker.type).toBe('quest') }) it('detects custom type', () => { const marker = createMarker(makeMarkerData({ image: 'custom' })) expect(marker.type).toBe('custom') }) it('extracts type from gfx path', () => { const marker = createMarker(makeMarkerData({ image: 'gfx/terobjs/mm/village' })) expect(marker.type).toBe('village') }) it('starts with null leaflet marker', () => { const marker = createMarker(makeMarkerData()) expect(marker.leafletMarker).toBeNull() }) it('add creates a leaflet marker for non-hidden markers', () => { const marker = createMarker(makeMarkerData()) const mapview = makeMapViewRef() marker.add(mapview) expect(mapview.map.unproject).toHaveBeenCalled() }) it('add does nothing for hidden markers', () => { const marker = createMarker(makeMarkerData({ hidden: true })) const mapview = makeMapViewRef() marker.add(mapview) expect(mapview.map.unproject).not.toHaveBeenCalled() }) it('update changes position and name', () => { const marker = createMarker(makeMarkerData()) const mapview = makeMapViewRef() marker.update(mapview, { ...makeMarkerData(), position: { x: 300, y: 400 }, name: 'Castle', }) expect(marker.position).toEqual({ x: 300, y: 400 }) expect(marker.name).toBe('Castle') }) it('setClickCallback and setContextMenu work', () => { const marker = createMarker(makeMarkerData()) const clickCb = vi.fn() const contextCb = vi.fn() marker.setClickCallback(clickCb) marker.setContextMenu(contextCb) }) it('remove on a marker without leaflet marker does nothing', () => { const marker = createMarker(makeMarkerData()) const mapview = makeMapViewRef() marker.remove(mapview) // should not throw expect(marker.leafletMarker).toBeNull() }) })