mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-19 13:36:48 +00:00
dc7d1f5e10
Vector basemaps rendered Arabic, Hebrew, Persian and Urdu place names as isolated letters in logical order — "القاهرة" drawn as "ة ر ه ا ق ل ا" — because neither GL engine loads its optional RTL text plugin by default and TREK never registered one. Raster basemaps hid the problem, since their labels are drawn server-side, so it only became visible for everyone when the default basemap became a vector style. Both engine entry points now register the plugin lazily, so the payload is only fetched once a map actually paints RTL text and Latin-only users download nothing. The call is left with each engine because the two signatures genuinely differ: MapLibre takes (url, lazy) and returns a promise, Mapbox takes (url, callback, deferred). The plugin is bundled rather than loaded from a CDN: TREK is offline-first and the production CSP is script-src 'self', so a remote plugin URL would be refused by the worker that imports it. Bundling also puts it in the Workbox precache, so shaping keeps working offline. It needs a resolve alias because the package publishes only its ESM/WASM entry point through "exports" while setRTLTextPlugin requires the classic script in dist/ — the alias is shared by the build and test configs so the two cannot drift.
39 lines
1.3 KiB
TypeScript
39 lines
1.3 KiB
TypeScript
import { describe, expect, it, vi } from 'vitest'
|
|
import { registerRtlTextPlugin } from './rtlText'
|
|
|
|
describe('registerRtlTextPlugin', () => {
|
|
it('runs the engine-supplied registration', () => {
|
|
const register = vi.fn()
|
|
|
|
expect(registerRtlTextPlugin(register)).toBe(true)
|
|
expect(register).toHaveBeenCalledTimes(1)
|
|
})
|
|
|
|
// Registering twice is how the engines report it: Mapbox throws.
|
|
it('never lets a refused registration break map creation', () => {
|
|
const register = vi.fn(() => {
|
|
throw new Error('setRTLTextPlugin cannot be called multiple times.')
|
|
})
|
|
|
|
expect(() => registerRtlTextPlugin(register)).not.toThrow()
|
|
expect(registerRtlTextPlugin(register)).toBe(false)
|
|
})
|
|
|
|
// MapLibre reports the same by rejecting, and an unhandled rejection would
|
|
// reach the console for something the user cannot act on.
|
|
it('swallows a rejected registration promise', async () => {
|
|
const onUnhandled = vi.fn()
|
|
process.on('unhandledRejection', onUnhandled)
|
|
|
|
expect(registerRtlTextPlugin(() => Promise.reject(new Error('404')))).toBe(true)
|
|
await new Promise(resolve => setTimeout(resolve, 0))
|
|
process.off('unhandledRejection', onUnhandled)
|
|
|
|
expect(onUnhandled).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('leaves a resolved promise alone', async () => {
|
|
expect(registerRtlTextPlugin(() => Promise.resolve())).toBe(true)
|
|
})
|
|
})
|