Files
TREK/client/src/components/Map/rtlText.test.ts
T
Mohamed Elkmeshi dc7d1f5e10 fix(maps): register the RTL text plugin so Arabic labels join
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.
2026-09-04 19:53:33 +02:00

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)
})
})