refactor: isolate Location controls and cancellable search

This commit is contained in:
Sameh Khamis committed 2026-09-12 22:55:16 -07:00
1 parent 20c1611354
commit ea77b49482
16 files changed
+604 -245

No files matched your search

+44
View File
@@ -0,0 +1,44 @@
import assert from 'node:assert/strict';
import test from 'node:test';
import { LocationControls } from './locationControls.js';
function node() {
const classes = new Set();
return {
children: [], dataset: {}, listeners: new Map(), className: '', textContent: '',
classList: { add: (...names) => names.forEach(name => classes.add(name)), remove: (...names) => names.forEach(name => classes.delete(name)), contains: name => classes.has(name), toggle(name, enabled = !classes.has(name)) { if(enabled) classes.add(name); else classes.delete(name); } },
addEventListener(name, callback) { if(!this.listeners.has(name)) this.listeners.set(name,new Set()); this.listeners.get(name).add(callback); },
removeEventListener(name, callback) { this.listeners.get(name)?.delete(callback); },
fire(name,event={}) { for(const callback of this.listeners.get(name)||[]) callback(event); },
appendChild(child) { this.children.push(child); child.parent=this; },
append(...children) { for(const child of children) if(typeof child!=='string') this.appendChild(child); },
replaceChildren() { this.children=[]; },
remove() { if(this.parent) this.parent.children=this.parent.children.filter(child=>child!==this); },
querySelectorAll(selector) { return this.children.flatMap(child=>[...(child.className===selector.slice(1)?[child]:[]),...child.querySelectorAll(selector)]); },
focus() { this.focused=true; },
};
}
function fixture() {
const elements={pills:node(),poiRow:node(),divider:node(),search:node(),searchToggle:node(),resetButtons:[node(),node()],statusCity:node(),statusPoi:node()};
const doc=node();doc.createElement=node;doc.body=node();
const cities={a:{name:'City A',pois:[{name:'First'},{name:'Second'}]},b:{name:'City B',pois:[{name:'Elsewhere'}]}};
const calls=[];const frames=new Map();const cancelled=[];let next=0;
const controls=new LocationControls({elements,cities,getExpandedCity:()=> 'a',onCity:id=>calls.push(['city',id]),onPoi:(id,index)=>calls.push(['poi',id,index]),onSearch:query=>calls.push(['search',query]),onReset:()=>calls.push(['reset']),doc,requestFrame:fn=>{const id=next++;frames.set(id,fn);return id},cancelFrame:id=>cancelled.push(id)});
return {elements,doc,controls,calls,frames,cancelled};
}
test('hiding a POI row cancels frame zero and rejects an already queued expansion', () => {
const f=fixture();f.controls.showPois('a');const callback=f.frames.get(0);f.controls.hidePois();callback();
assert.deepEqual(f.cancelled,[0]);assert.equal(f.elements.poiRow.classList.contains('expanded'),false);assert.equal(f.elements.divider.classList.contains('visible'),false);
});
test('replacing POIs removes old click actions and presents the final row', () => {
const f=fixture();f.controls.showPois('a');const old=f.elements.poiRow.children[0];f.controls.showPois('b');old.fire('click');
assert.deepEqual(f.calls,[]);f.elements.poiRow.children[0].fire('click');assert.deepEqual(f.calls,[['poi','b',0]]);
f.frames.get(0)();assert.equal(f.elements.poiRow.classList.contains('expanded'),false);f.frames.get(1)();assert.equal(f.elements.poiRow.classList.contains('expanded'),true);
});
test('destruction revokes document, search, reset, city and POI actions and removes orbit UI', () => {
const f=fixture();f.controls.showPois('a');f.controls.createOrbitIndicator();assert.equal(f.doc.body.children.length,1);const city=f.elements.pills.children[0];const poi=f.elements.poiRow.children[0];f.controls.destroy();f.controls.destroy();
city.fire('click');poi.fire('click');f.elements.search.value='Place';f.elements.search.fire('keydown',{key:'Enter'});f.doc.fire('keydown',{key:'Q'});f.elements.resetButtons[0].fire('click');f.frames.get(0)();assert.deepEqual(f.calls,[]);assert.equal(f.doc.body.children.length,0);
});
test('location and POI keys route once while form controls retain typing', () => {
const f=fixture();f.doc.fire('keydown',{key:'W',target:{matches:()=>false}});f.doc.fire('keydown',{key:'Q',target:{matches:()=>true}});f.elements.resetButtons[1].fire('click');assert.deepEqual(f.calls,[['poi','a',1],['reset']]);
});