diff --git a/client/src/components/Settings/MapSettingsTab.test.tsx b/client/src/components/Settings/MapSettingsTab.test.tsx index f1c5c8558..e366cb18f 100644 --- a/client/src/components/Settings/MapSettingsTab.test.tsx +++ b/client/src/components/Settings/MapSettingsTab.test.tsx @@ -8,10 +8,11 @@ import { buildUser, buildSettings } from '../../../tests/helpers/factories'; import { ToastContainer } from '../shared/Toast'; import MapSettingsTab from './MapSettingsTab'; -// Mock MapView to avoid Leaflet DOM issues in jsdom +// Mock MapView to avoid Leaflet DOM issues in jsdom. tileUrl is surfaced because +// the preview has to draw the basemap being configured, key included. vi.mock('../Map/MapView', () => ({ - MapView: ({ onMapClick }: { onMapClick?: (info: { latlng: { lat: number; lng: number } }) => void }) => ( -
onMapClick?.({ latlng: { lat: 51.5, lng: -0.1 } })} /> + MapView: ({ onMapClick, tileUrl }: { onMapClick?: (info: { latlng: { lat: number; lng: number } }) => void; tileUrl?: string }) => ( +
onMapClick?.({ latlng: { lat: 51.5, lng: -0.1 } })} /> ), })); @@ -394,6 +395,27 @@ describe('MapSettingsTab – CARTO key', () => { expect(updateSettings).toHaveBeenCalledWith(expect.objectContaining({ carto_api_key: 'demo-key' })); }); + it('FE-COMP-MAP-033b: the preview draws the CARTO basemap being configured, not the app default', async () => { + // The fields hold what the user is editing, not what useTileUrl resolved, so + // the key has to be put back on before the preview reads the template. + // Without it the preview resolves a keyless CARTO url, silently falls back to + // the default vector style, and shows a basemap nobody chose. + const user = userEvent.setup(); + seedStore(useSettingsStore, { + settings: buildSettings({ map_tile_url: CARTO_DARK_TILES, carto_api_key: 'demo-key' }), + }); + render(); + + await waitFor(() => { + expect(screen.getByTestId('map-view').getAttribute('data-tile-url')).toContain('key=demo-key'); + }); + + await user.clear(cartoInput()); + await waitFor(() => { + expect(screen.getByTestId('map-view').getAttribute('data-tile-url')).not.toContain('key='); + }); + }); + it('FE-COMP-MAP-034: a CARTO template without a key explains the watermark until one is typed', async () => { const user = userEvent.setup(); seedStore(useSettingsStore, { diff --git a/client/src/components/Settings/MapSettingsTab.tsx b/client/src/components/Settings/MapSettingsTab.tsx index 4476508fa..aaa7f74ee 100644 --- a/client/src/components/Settings/MapSettingsTab.tsx +++ b/client/src/components/Settings/MapSettingsTab.tsx @@ -11,6 +11,7 @@ import ErrorBoundary from '../shared/ErrorBoundary' import { GlMapPreviewMapbox, GlMapPreviewMaplibre } from '../Map/glLazy' import Section from './Section' import ToggleSwitch from './ToggleSwitch' +import { withTileApiKey } from '../../utils/tileUrl' import type { Place } from '../../types' import { MAPBOX_DEFAULT_STYLE, @@ -473,7 +474,12 @@ export default function MapSettingsTab(): React.ReactElement { onMarkerClick: null, onMapClick: null, onMapContextMenu: null, - tileUrl: mapTileUrl, + // With the key on it, or the preview resolves the template as a + // keyless CARTO one and quietly shows the app default instead of + // the basemap being configured. The fields hold what the user is + // editing rather than what useTileUrl already resolved, so the key + // has to be put back on here. + tileUrl: withTileApiKey(mapTileUrl, cartoKey), fitKey: null, dayOrderMap: [], leftWidth: 0,