diff --git a/frontend/__tests__/unit/components/ChapterMap.test.tsx b/frontend/__tests__/unit/components/ChapterMap.test.tsx
index d16027d496..bbdc01e5f5 100644
--- a/frontend/__tests__/unit/components/ChapterMap.test.tsx
+++ b/frontend/__tests__/unit/components/ChapterMap.test.tsx
@@ -1,4 +1,5 @@
import { render } from '@testing-library/react'
+import * as L from 'leaflet'
import { Chapter } from 'types/chapter'
import ChapterMap from 'components/ChapterMap'
@@ -113,8 +114,6 @@ describe('ChapterMap', () => {
describe('Map initialization', () => {
it('initializes leaflet map with correct configuration', () => {
- // eslint-disable-next-line @typescript-eslint/no-require-imports
- const L = require('leaflet')
render()
expect(L.map).toHaveBeenCalledWith('chapter-map', {
worldCopyJump: false,
@@ -128,9 +127,6 @@ describe('ChapterMap', () => {
})
it('adds tile layer to the map', () => {
- // eslint-disable-next-line @typescript-eslint/no-require-imports
- const L = require('leaflet')
-
render()
expect(L.tileLayer).toHaveBeenCalledWith(
'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
@@ -143,9 +139,6 @@ describe('ChapterMap', () => {
})
it('creates and adds marker cluster group', () => {
- // eslint-disable-next-line @typescript-eslint/no-require-imports
- const L = require('leaflet')
-
render()
expect(L.markerClusterGroup).toHaveBeenCalled()
expect(mockMap.addLayer).toHaveBeenCalledWith(mockMarkerClusterGroup)
@@ -154,19 +147,45 @@ describe('ChapterMap', () => {
describe('Markers', () => {
it('creates markers for each chapter', () => {
- // eslint-disable-next-line @typescript-eslint/no-require-imports
- const L = require('leaflet')
-
render()
expect(L.marker).toHaveBeenCalledTimes(2)
expect(L.marker).toHaveBeenCalledWith([40.7128, -74.006], { icon: mockIcon })
expect(L.marker).toHaveBeenCalledWith([51.5074, -0.1278], { icon: mockIcon })
})
- it('creates marker icons with correct configuration', () => {
- // eslint-disable-next-line @typescript-eslint/no-require-imports
- const L = require('leaflet')
+ it('filters out virtual chapters when latitude longitude undefined', () => {
+ const virtualChapterData: Chapter[] = [
+ mockChapterData[0],
+ {
+ // A virtual chapter with no location data
+ ...mockChapterData[1],
+ _geoloc: undefined,
+ geoLocation: undefined,
+ },
+ ]
+
+ render()
+ expect(L.marker).toHaveBeenCalledTimes(1)
+ expect(L.marker).not.toHaveBeenCalledWith([undefined, undefined], { icon: mockIcon })
+ })
+
+ it('filters out virtual chapters when latitude longitude null', () => {
+ const virtualChapterData: Chapter[] = [
+ mockChapterData[0],
+ {
+ // A virtual chapter with no location data
+ ...mockChapterData[1],
+ _geoloc: null,
+ geoLocation: null,
+ },
+ ]
+
+ render()
+ expect(L.marker).toHaveBeenCalledTimes(1)
+ expect(L.marker).not.toHaveBeenCalledWith([null, null], { icon: mockIcon })
+ })
+ it('creates marker icons with correct configuration', () => {
render()
expect(L.Icon).toHaveBeenCalledWith({
iconAnchor: [12, 41],
@@ -185,8 +204,6 @@ describe('ChapterMap', () => {
})
it('handles chapters with missing _geoloc but present geolocation', () => {
- // eslint-disable-next-line @typescript-eslint/no-require-imports
- const L = require('leaflet')
const chapterWithoutGeoloc: Chapter[] = [
{
...mockChapterData[0],
@@ -198,13 +215,24 @@ describe('ChapterMap', () => {
render()
expect(L.marker).toHaveBeenCalledWith([35.6762, 139.6503], { icon: mockIcon })
})
+
+ it('handles chapters with 0 coordinates correctly', () => {
+ const chapterWithZeroCoords: Chapter[] = [
+ {
+ ...mockChapterData[0],
+ _geoloc: { lat: 0, lng: 0 },
+ geoLocation: { lat: 0, lng: 0 },
+ },
+ ]
+
+ render()
+ expect(L.marker).toHaveBeenCalledTimes(1)
+ expect(L.marker).toHaveBeenCalledWith([0, 0], { icon: mockIcon })
+ })
})
describe('Popups', () => {
it('creates popups for each marker', () => {
- // eslint-disable-next-line @typescript-eslint/no-require-imports
- const L = require('leaflet')
-
render()
expect(L.popup).toHaveBeenCalledTimes(2)
expect(mockMarker.bindPopup).toHaveBeenCalledTimes(2)
@@ -223,8 +251,6 @@ describe('ChapterMap', () => {
describe('Local View', () => {
it('sets local view when showLocal is true', () => {
- // eslint-disable-next-line @typescript-eslint/no-require-imports
- const L = require('leaflet')
render()
expect(mockMap.setView).toHaveBeenCalledWith([40.7128, -74.006], 7)
diff --git a/frontend/src/components/ChapterMap.tsx b/frontend/src/components/ChapterMap.tsx
index 36c360aca5..e753adadea 100644
--- a/frontend/src/components/ChapterMap.tsx
+++ b/frontend/src/components/ChapterMap.tsx
@@ -48,7 +48,13 @@ const ChapterMap = ({
const markerClusterGroup = markerClusterRef.current
- const markers = geoLocData.map((chapter) => {
+ const validGeoLocData = geoLocData.filter((chapter) => {
+ const lat = chapter._geoloc?.lat ?? chapter.geoLocation?.lat
+ const lng = chapter._geoloc?.lng ?? chapter.geoLocation?.lng
+ return typeof lat === 'number' && typeof lng === 'number'
+ })
+
+ const markers = validGeoLocData.map((chapter) => {
const markerIcon = new L.Icon({
iconAnchor: [12, 41],
iconRetinaUrl: '/img/marker-icon-2x.png',
@@ -61,8 +67,8 @@ const ChapterMap = ({
const marker = L.marker(
[
- chapter._geoloc?.lat || chapter.geoLocation?.lat,
- chapter._geoloc?.lng || chapter.geoLocation?.lng,
+ chapter._geoloc?.lat ?? chapter.geoLocation?.lat,
+ chapter._geoloc?.lng ?? chapter.geoLocation?.lng,
],
{ icon: markerIcon }
)
@@ -80,21 +86,21 @@ const ChapterMap = ({
markerClusterGroup.addLayers(markers)
- if (showLocal && geoLocData.length > 0) {
+ if (showLocal && validGeoLocData.length > 0) {
const maxNearestChapters = 5
- const localChapters = geoLocData.slice(0, maxNearestChapters - 1)
+ const localChapters = validGeoLocData.slice(0, maxNearestChapters - 1)
const localBounds = L.latLngBounds(
localChapters.map((chapter) => [
- chapter._geoloc?.lat || chapter.geoLocation?.lat,
- chapter._geoloc?.lng || chapter.geoLocation?.lng,
+ chapter._geoloc?.lat ?? chapter.geoLocation?.lat,
+ chapter._geoloc?.lng ?? chapter.geoLocation?.lng,
])
)
const maxZoom = 7
- const nearestChapter = geoLocData[0]
+ const nearestChapter = validGeoLocData[0]
map.setView(
[
- nearestChapter._geoloc?.lat || nearestChapter.geoLocation?.lat,
- nearestChapter._geoloc?.lng || nearestChapter.geoLocation?.lng,
+ nearestChapter._geoloc?.lat ?? nearestChapter.geoLocation?.lat,
+ nearestChapter._geoloc?.lng ?? nearestChapter.geoLocation?.lng,
],
maxZoom
)