mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-19 21:46:49 +00:00
98e2938033
A place with an uploaded image showed a plain disc of its category colour on the map, while a picked suggestion looked fine. The marker sized its img with width and height attributes, and stylesheet rules beat those: Tailwind's preflight gives every img height: auto, and Leaflet's marker pane adds width: auto. Suggested and auto photos reach the marker as 48px square thumbs, so nothing showed. A phone photo kept its own proportions on the GL map, a sliver inside the circle, and its full pixel size on Leaflet, where only the rounded-off corner of a 4000px image lands inside the circle. Both maps now build the img through one helper that sizes it in its style, so object-fit: cover crops any photo to the circle. The thumb loading on both maps was keyed on place ids, so a change of picture under the same place went unnoticed until a reload: - Taking an upload off a place left the category dot instead of bringing its auto photo back. - Picking another suggested photo kept the thumb of the first one, which was cached under the provider id. A picked photo is now its own cache key.
68 lines
3.3 KiB
TypeScript
68 lines
3.3 KiB
TypeScript
import { describe, it, expect } from 'vitest'
|
|
import { isCustomPlaceImage, markerPhotoHtml, photoCacheKey, photoSourcesKey } from './placePhoto'
|
|
|
|
function imgOf(html: string): HTMLImageElement {
|
|
const holder = document.createElement('div')
|
|
holder.innerHTML = html
|
|
return holder.querySelector('img')!
|
|
}
|
|
|
|
describe('isCustomPlaceImage', () => {
|
|
it('FE-MAP-PLACEPHOTO-001: an upload or an inline image is shown as it is, a provider photo is not', () => {
|
|
expect(isCustomPlaceImage('/uploads/places/a.jpg')).toBe(true)
|
|
expect(isCustomPlaceImage('data:image/png;base64,AAA')).toBe(true)
|
|
expect(isCustomPlaceImage('/api/maps/place-photo/gp-1~p0/bytes')).toBe(false)
|
|
expect(isCustomPlaceImage(null)).toBe(false)
|
|
})
|
|
})
|
|
|
|
describe('markerPhotoHtml', () => {
|
|
it('FE-MAP-PLACEPHOTO-002: sizes the picture by its style, where no stylesheet rule can undo it', () => {
|
|
// Preflight's `height: auto` and Leaflet's `width: auto` both outrank a width or
|
|
// height attribute, so a photo that is not a small square has to be pinned here.
|
|
const img = imgOf(markerPhotoHtml('/uploads/places/wide.jpg'))
|
|
expect(img.getAttribute('src')).toBe('/uploads/places/wide.jpg')
|
|
expect(img.style.width).toBe('100%')
|
|
expect(img.style.height).toBe('100%')
|
|
expect(img.hasAttribute('width')).toBe(false)
|
|
expect(img.hasAttribute('height')).toBe(false)
|
|
})
|
|
|
|
it('FE-MAP-PLACEPHOTO-003: escapes the url, which a user can set', () => {
|
|
const html = markerPhotoHtml('/uploads/x" onerror="alert(1)" y="')
|
|
expect(html).not.toContain('onerror="alert(1)"')
|
|
expect(imgOf(html).getAttribute('src')).toBe('/uploads/x" onerror="alert(1)" y="')
|
|
})
|
|
})
|
|
|
|
describe('photoCacheKey', () => {
|
|
it('FE-MAP-PLACEPHOTO-004: a picked provider photo is its own key, ahead of the provider id', () => {
|
|
expect(photoCacheKey({ image_url: '/api/maps/place-photo/gp-1~p2/bytes', google_place_id: 'gp-1', lat: 1, lng: 2 }))
|
|
.toBe('/api/maps/place-photo/gp-1~p2/bytes')
|
|
})
|
|
|
|
it('FE-MAP-PLACEPHOTO-005: otherwise the provider id, then the coordinates, then nothing', () => {
|
|
expect(photoCacheKey({ image_url: '/uploads/places/a.jpg', google_place_id: 'gp-1', osm_id: 'node/1' })).toBe('gp-1')
|
|
expect(photoCacheKey({ osm_id: 'node/1', lat: 1, lng: 2 })).toBe('node/1')
|
|
expect(photoCacheKey({ lat: 0, lng: 0 })).toBe('0,0')
|
|
expect(photoCacheKey({ image_url: 'https://example.com/a.jpg', lat: null, lng: null })).toBe('')
|
|
})
|
|
})
|
|
|
|
describe('photoSourcesKey', () => {
|
|
const place = { id: 7, google_place_id: 'gp-7', lat: 48, lng: 2 }
|
|
|
|
it('FE-MAP-PLACEPHOTO-006: changes when an upload comes off or another photo is picked', () => {
|
|
const withUpload = photoSourcesKey([{ ...place, image_url: '/uploads/places/a.jpg' }])
|
|
const bare = photoSourcesKey([{ ...place, image_url: null }])
|
|
const picked = photoSourcesKey([{ ...place, image_url: '/api/maps/place-photo/gp-7~p0/bytes' }])
|
|
const pickedAgain = photoSourcesKey([{ ...place, image_url: '/api/maps/place-photo/gp-7~p1/bytes' }])
|
|
expect(new Set([withUpload, bare, picked, pickedAgain]).size).toBe(4)
|
|
})
|
|
|
|
it('FE-MAP-PLACEPHOTO-007: stays put when one upload replaces another, which needs no thumb', () => {
|
|
expect(photoSourcesKey([{ ...place, image_url: '/uploads/places/a.jpg' }]))
|
|
.toBe(photoSourcesKey([{ ...place, image_url: '/uploads/places/b.jpg' }]))
|
|
})
|
|
})
|