mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-19 05:26:47 +00:00
fix(map): give the Leaflet map its own zoom ceiling, so a vector basemap cannot take the planner down
Opening a trip on 4.1.0 could land on the error boundary with "Map has no maxZoom specified", and so could the map settings tab, which left no screen from which to pick a different basemap. Leaflet answers getMaxZoom() from the map options first and otherwise from a layer that brought one, and only a GridLayer ever contributes via its beforeAdd hook. A vector basemap is a GL canvas on a plain L.Layer, so it contributes nothing, and MapContainer set no ceiling of its own. MarkerClusterGroup.onAdd refuses an infinite one by throwing, before any clustering, so an empty trip hit it too. That path opened when the default basemap became a MapLibre style. It reaches further than an operator choosing OpenFreeMap: resolveTileUrl sends a keyless CARTO template to the app default, which is now a vector style, so every instance still carrying the old CARTO basemap fell into it on upgrade. The ceiling belongs on the map rather than on the base layer, because it has to hold whichever of the three branches renders. 19 matches what the raster and satellite layers already carried, so nothing changes for the maps that worked. SharedTripPage gets the same treatment: it has no cluster to throw, but it draws the same vector basemap and its fitBounds asks for a ceiling. mapZoomCeiling.test.ts pins Leaflet's own semantics against the real library rather than a mock, since a mocked react-leaflet would have kept passing through all of this.
This commit is contained in:
@@ -5,6 +5,7 @@ import { act, fireEvent, waitFor } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import { resetAllStores } from '../../../tests/helpers/store'
|
||||
import { buildPlace, buildReservation } from '../../../tests/helpers/factories'
|
||||
import { MAP_MAX_ZOOM } from '../../constants/mapDefaults'
|
||||
import { useAuthStore } from '../../store/authStore'
|
||||
import { CATEGORY_ICON_MAP } from '../shared/categoryIcons'
|
||||
import * as photoService from '../../services/photoService'
|
||||
@@ -48,9 +49,10 @@ vi.mock('../../hooks/useGeolocation', () => ({
|
||||
const thumbCallbacks = vi.hoisted(() => new Map<string, (thumb: string) => void>())
|
||||
|
||||
vi.mock('react-leaflet', () => ({
|
||||
// center/zoom are surfaced so tests can assert the camera the map is built with.
|
||||
MapContainer: ({ children, center, zoom }: any) => (
|
||||
<div data-testid="map-container" data-center={JSON.stringify(center)} data-zoom={zoom}>{children}</div>
|
||||
// center/zoom are surfaced so tests can assert the camera the map is built
|
||||
// with; maxZoom because a cluster refuses to attach to a map without one.
|
||||
MapContainer: ({ children, center, zoom, maxZoom }: any) => (
|
||||
<div data-testid="map-container" data-center={JSON.stringify(center)} data-zoom={zoom} data-maxzoom={maxZoom}>{children}</div>
|
||||
),
|
||||
TileLayer: () => <div data-testid="tile-layer" />,
|
||||
Marker: ({ children, eventHandlers, position, icon, zIndexOffset }: any) => (
|
||||
@@ -245,6 +247,14 @@ describe('MapView', () => {
|
||||
expect(screen.getByTestId('cluster-group')).toBeTruthy()
|
||||
})
|
||||
|
||||
it('FE-COMP-MAPVIEW-010b: the map carries a zoom ceiling of its own, whatever the basemap is', () => {
|
||||
// Without it, a vector basemap leaves the map with none and the cluster
|
||||
// above throws on attach, taking the planner to the error boundary. The
|
||||
// ceiling has to sit on the map because only a GridLayer can contribute one.
|
||||
render(<MapView places={[buildMapPlace({ lat: 48.8584, lng: 2.2945 })]} />)
|
||||
expect(screen.getByTestId('map-container').getAttribute('data-maxzoom')).toBe(String(MAP_MAX_ZOOM))
|
||||
})
|
||||
|
||||
it('FE-COMP-MAPVIEW-011: renders the route polyline; travel times are no longer drawn on the map', () => {
|
||||
const route = [[[48.0, 2.0], [49.0, 3.0]]] as unknown as [number, number][][]
|
||||
render(<MapView route={route} />)
|
||||
|
||||
Reference in New Issue
Block a user