// search.mjs — search by coordinates, H3 cell id and pin name const type = s => [{ type: 'key', id: 'kb', actions: [...s].flatMap(c => [{ type: 'keyDown', value: c }, { type: 'keyUp', value: c }]) }]; const ENTER = '', ESC = ''; const items = `return [...document.querySelectorAll('#suggest .item')].map(e => e.textContent);`; export const steps = [ { name: '/ focuses search', wait: 4000, actions: type('/'), js: `return document.activeElement.id;`, expect: v => v === 'search' }, { name: 'coordinates suggest', actions: type('40N 10W'), js: items, expect: v => v.length === 1 && v[0].startsWith('40.000° N') }, { name: 'Enter flies there with a marker', actions: type(ENTER), settle: 700, js: `const s = window.mapViewer.view.getState(); return { s, n: document.querySelectorAll('.marker.search').length };`, expect: v => Math.abs(v.s.lat - 40) < 0.01 && Math.abs(v.s.lon + 10) < 0.01 && v.s.alt <= 0.6 + 1e-9 && v.n === 1 }, { name: 'Esc clears the marker', actions: type(ESC), js: `return document.querySelectorAll('.marker.search').length;`, expect: v => v === 0 }, { name: 'cell id suggests', js: `const c = await (await fetch('/api/cell?lat=-20&lon=100')).json(); const i = document.getElementById('search'); i.focus(); i.value = c.cell; i.dispatchEvent(new Event('input')); return document.querySelectorAll('#suggest .item').length;`, expect: v => v === 1 }, { name: 'Enter resolves the cell', actions: type(ENTER), settle: 900, js: `const s = window.mapViewer.view.getState(); return Math.abs(s.lat + 20) < 0.6 && Math.abs(s.lon - 100) < 0.6;`, expect: v => v === true }, { name: 'pins are searchable', js: `await fetch('/api/pins', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'Searchable Ford', lat: 12, lon: 34 }) }); await window.mapViewer.pins.load(); const i = document.getElementById('search'); i.focus(); i.value = 'ford'; i.dispatchEvent(new Event('input'));` + items, expect: v => v.some(t => t.startsWith('Searchable Ford')) }, { name: 'Enter on a pin flies without a marker', actions: type(ENTER), settle: 700, js: `const s = window.mapViewer.view.getState(); return [s.lat, s.lon, document.querySelectorAll('.marker.search').length];`, expect: ([la, lo, n]) => Math.abs(la - 12) < 0.01 && Math.abs(lo - 34) < 0.01 && n === 0 }, { name: 'measure two points, focus search', js: `const a = window.mapViewer; a.showTab('measure'); a.measure.add({ lat: 1, lon: 2 }); a.measure.add({ lat: 3, lon: 4 }); a.measureChanged(); document.getElementById('search').focus(); return a.measure.points.length;`, expect: v => v === 2 }, { name: 'Esc in the search box keeps the measure path', actions: type(ESC), expect: v => v === 2, js: `return window.mapViewer.measure.points.length;` }, { name: 'junk suggests nothing', js: `const i = document.getElementById('search'); i.value = '95 10'; i.dispatchEvent(new Event('input')); return document.getElementById('suggest').hidden;`, expect: v => v === true }, ];