Files
TREK/client/src/components/Map/MapCompassPill.test.tsx
T
Maurice 01ddcc63bb feat(mobile): two calm round controls a side on the map, no extra buttons
The phone map stacked four controls on the right and one on the left, in
three different looks. Now each side has two at most, all in one frosted
style, 20px off the edge and 8px apart: the whole-trip overview and locate on
the right, the base layer and the Dawarich route on the left, with the compass
appearing only while the map is turned off north.

The map's own places filter button and sheet are gone: the places tab carries
the same filter, and the map's pins follow it. The jump-to-today button beside
the day rail is gone too, since today's chip is already marked.

Also fixes a leftover of the segmented-control change that broke the parse.
2026-11-06 15:02:49 +01:00

103 lines
3.8 KiB
TypeScript

// FE-COMP-MAPCOMPASS-001 to FE-COMP-MAPCOMPASS-007
import React from 'react'
import { describe, it, expect, vi } from 'vitest'
import { render, screen, fireEvent, act } from '../../../tests/helpers/render'
import { MapCompassPill, type CompassMap } from './MapCompassPill'
function fakeCompassMap(initialBearing = 0) {
const listeners: Array<() => void> = []
let bearing = initialBearing
const map = {
getBearing: vi.fn(() => bearing),
on: vi.fn((_type: 'rotate', fn: () => void) => { listeners.push(fn) }),
off: vi.fn((_type: 'rotate', fn: () => void) => {
const i = listeners.indexOf(fn)
if (i >= 0) listeners.splice(i, 1)
}),
easeTo: vi.fn(),
}
return {
map: map as unknown as CompassMap,
spies: map,
listenerCount: () => listeners.length,
rotateTo: (next: number) => {
bearing = next
act(() => { listeners.forEach(fn => fn()) })
},
}
}
const needle = () => screen.getByRole('button', { name: 'Reset north' }).querySelector('svg') as SVGElement
describe('MapCompassPill', () => {
it('FE-COMP-MAPCOMPASS-001: points the needle against the current map bearing', () => {
const { map } = fakeCompassMap(45)
render(<MapCompassPill map={map} />)
// The map rotated 45° clockwise, so the needle turns 45° back to keep pointing north.
expect(needle().style.transform).toBe('rotate(-45deg)')
})
it('FE-COMP-MAPCOMPASS-002: follows the map while it rotates', () => {
const compass = fakeCompassMap(0)
render(<MapCompassPill map={compass.map} />)
expect(needle().style.transform).toBe('rotate(0deg)')
compass.rotateTo(120)
expect(needle().style.transform).toBe('rotate(-120deg)')
})
it('FE-COMP-MAPCOMPASS-003: snaps the camera back to north and flat on click', () => {
const compass = fakeCompassMap(75)
render(<MapCompassPill map={compass.map} />)
fireEvent.click(screen.getByRole('button', { name: 'Reset north' }))
expect(compass.spies.easeTo).toHaveBeenCalledWith({ bearing: 0, pitch: 0, duration: 300 })
})
it('FE-COMP-MAPCOMPASS-004: unsubscribes from the rotate event on unmount', () => {
const compass = fakeCompassMap(0)
const { unmount } = render(<MapCompassPill map={compass.map} />)
expect(compass.listenerCount()).toBe(1)
unmount()
expect(compass.spies.off).toHaveBeenCalledWith('rotate', expect.any(Function))
expect(compass.listenerCount()).toBe(0)
})
it('FE-COMP-MAPCOMPASS-005: resubscribes when the map instance is swapped (style rebuild)', () => {
const first = fakeCompassMap(10)
const second = fakeCompassMap(200)
const { rerender } = render(<MapCompassPill map={first.map} />)
rerender(<MapCompassPill map={second.map} />)
expect(first.listenerCount()).toBe(0)
expect(second.listenerCount()).toBe(1)
expect(needle().style.transform).toBe('rotate(-200deg)')
})
it('FE-COMP-MAPCOMPASS-006: highlights the button on hover and clears it again', () => {
const { map } = fakeCompassMap(0)
render(<MapCompassPill map={map} />)
const button = screen.getByRole('button', { name: 'Reset north' })
fireEvent.mouseEnter(button)
expect(button.style.background).toBe('var(--bg-hover)')
fireEvent.mouseLeave(button)
expect(button.style.background).toBe('transparent')
})
})
describe('MapCompassPill on the phone map', () => {
it('FE-COMP-MAPCOMPASS-007: appears only while the map is turned off north', () => {
const { map, rotateTo } = fakeCompassMap(0)
render(<MapCompassPill map={map} onlyWhenRotated />)
expect(screen.queryByRole('button', { name: 'Reset north' })).not.toBeInTheDocument()
rotateTo(30)
expect(screen.getByRole('button', { name: 'Reset north' })).toBeInTheDocument()
rotateTo(0)
expect(screen.queryByRole('button', { name: 'Reset north' })).not.toBeInTheDocument()
})
})