Files
TREK/client/src/components/PDF/tripMapImage.test.ts
T
Maurice e28bd2fc99 fix(maps): draw with Leaflet wherever WebGL2 is missing
MapLibre 6 and Mapbox GL 3 both throw out of their Map constructor without
WebGL2. Every place that builds a GL map now asks one helper first,
components/Map/glSupport.ts, and a browser without WebGL2 gets the Leaflet
map with the user's tiles instead of a map that fails to start:

- the trip map (MapViewAuto) and the journey maps (JourneyMapAuto) pick
  their renderer through useGlRenderer, which folds in the Mapbox token
  rule they each had;
- the settings preview, desktop and phone, shows the Leaflet preview
  through useMapSettingsForm and says why under it;
- the tour planner keeps the 2D map when 3D is asked for and says that
  3D needs WebGL2;
- the PDF route map and the Leaflet vector basemap already fell back and
  now report a GPU failure too.

Behind the probe, buildGlMap wraps each constructor (MapViewGL,
JourneyMapGL, the settings preview, the terrain map, the PDF map). A GPU
that claims WebGL2 and still refuses the context is reported through
utils/webgl, which turns the answer to no and tells every mounted map,
so they switch to Leaflet without a reload; any other error is still
thrown. Two new strings, map.webgl2.fallback and map.webgl2.terrain, in
all 27 locales.
2026-10-24 22:41:56 +00:00

48 lines
2.0 KiB
TypeScript

import { describe, it, expect, vi, beforeEach } from 'vitest'
import type { TripOverviewDay } from '../Map/tripRouteGeometry'
vi.mock('../../utils/webgl', () => ({ hasWebGL: vi.fn(() => true), resetWebGLProbe: vi.fn(), reportWebGLFailure: vi.fn() }))
const { hasWebGL } = await import('../../utils/webgl')
const { renderTripMapImage } = await import('./tripMapImage')
const day = (over: Partial<TripOverviewDay> = {}): TripOverviewDay => ({
dayId: 1, dayNumber: 1, date: null, title: null, color: { line: '#0a84ff', casing: '#0a5cc2' },
lines: [[[48.86, 2.35], [48.88, 2.40]]],
segments: [], distance: 0, duration: 0, modes: [], ...over,
})
const opts = { width: 720, height: 420, style: null, formatDistance: (km: number) => `${km} km` }
beforeEach(() => {
vi.mocked(hasWebGL).mockReturnValue(true)
document.body.innerHTML = ''
})
describe('renderTripMapImage', () => {
it('FE-PDF-MAPIMG-001: gives up without WebGL, before touching the map engine', async () => {
vi.mocked(hasWebGL).mockReturnValue(false)
expect(await renderTripMapImage([day()], opts)).toBeNull()
})
it('FE-PDF-MAPIMG-002: gives up when there is no route to frame', async () => {
expect(await renderTripMapImage([], opts)).toBeNull()
expect(await renderTripMapImage([day({ lines: [[[48.86, 2.35]]] })], opts)).toBeNull()
})
it('FE-PDF-MAPIMG-003: returns null rather than throwing when the engine fails', async () => {
// jsdom has no WebGL implementation behind the probe, so constructing the map
// throws — the export must survive that and fall back to the outline map.
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {})
expect(await renderTripMapImage([day()], opts)).toBeNull()
warn.mockRestore()
})
it('FE-PDF-MAPIMG-004: leaves no offscreen container behind', async () => {
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {})
await renderTripMapImage([day()], opts)
expect(document.body.children).toHaveLength(0)
warn.mockRestore()
})
})