Files
Investidor-V2/tests/frontend/territory-search-select.test.mjs
T

57 lines
3.9 KiB
JavaScript

import assert from 'node:assert/strict';
import test from 'node:test';
import fs from 'node:fs';
import {createRequire} from 'node:module';
import React from 'react';
import ts from 'typescript';
// Exercise the real component's event/state contract; this is not browser visual QA.
const require=createRequire(import.meta.url);
const source=fs.readFileSync(new URL('../../resources/js/components/territory-search-select.tsx',import.meta.url),'utf8');
const compiled=ts.transpileModule(source,{compilerOptions:{module:ts.ModuleKind.CommonJS,target:ts.ScriptTarget.ES2022,jsx:ts.JsxEmit.ReactJSX}}).outputText;
function harness(overrides={}){
const memory=[];let cursor=0;const chosen=[];
const hooks={...React,useState(initial){const i=cursor++;if(!(i in memory))memory[i]=initial;return[memory[i],value=>{memory[i]=typeof value==='function'?value(memory[i]):value;}];},useRef:()=>({current:null}),useEffect:()=>{}};
const module={exports:{}};
new Function('require','module','exports',compiled)(name=>name==='react'?hooks:require(name),module,module.exports);
const options=[{id:'province-a',name:'Nampula'},{id:'province-b',name:'Maputo Província'}];
const props={id:'territory',label:'Província',search:'',options,onSearch(query){props.search=query;},onChange(option){chosen.push(option);props.selected=option;},...overrides};
let tree;
const flat=node=>!node||typeof node!=='object'?[]:[node,...React.Children.toArray(node.props?.children).flatMap(flat)];
const render=()=>{cursor=0;tree=module.exports.default(props);return tree;};
const find=predicate=>flat(tree).find(predicate);
const input=()=>find(node=>node.type==='input');
const key=value=>input().props.onKeyDown({key:value,preventDefault(){}});
render();return{props,chosen,render,find,input,key,options};
}
test('one search input owns the dropdown; the separate select is absent',()=>{
const h=harness();assert.equal(h.find(node=>node.type==='select'),undefined);
assert.equal(h.input().props.role,'combobox');assert.equal(h.input().props['aria-expanded'],false);
h.input().props.onFocus();h.render();
assert.equal(h.input().props['aria-expanded'],true);
assert.ok(h.find(node=>node.props?.role==='listbox'));
h.find(node=>node.props?.role==='option'&&node.props.id==='territory-options-1').props.onClick();h.render();
assert.deepEqual(h.chosen,[h.options[1]]);assert.equal(h.input().props.value,'Maputo Província');
assert.equal(h.input().props['aria-expanded'],false);
});
test('typing and Escape preserve the existing selection until an option is explicitly chosen',()=>{
const selected={id:'saved',name:'Selecção guardada fora desta página'};const h=harness({selected});
h.input().props.onFocus();h.render();h.input().props.onChange({target:{value:'Map'}});h.render();
assert.equal(h.props.search,'Map');assert.deepEqual(h.chosen,[]);
h.key('Escape');h.render();assert.equal(h.input().props.value,selected.name);assert.deepEqual(h.chosen,[]);
});
test('arrow keys and Enter choose from the list; loading cannot commit an old result',()=>{
const h=harness();h.input().props.onFocus();h.render();h.key('ArrowDown');h.render();h.key('ArrowDown');h.render();
assert.equal(h.input().props['aria-activedescendant'],'territory-options-1');
h.key('Enter');h.render();assert.deepEqual(h.chosen,[h.options[1]]);
const busy=harness({loading:true});busy.input().props.onFocus();busy.render();busy.key('Enter');
assert.deepEqual(busy.chosen,[]);
});
test('clear is explicit; disabled dependent levels cannot expose the dropdown',()=>{
const h=harness({selected:{id:'saved',name:'Nampula'}});
h.find(node=>node.props?.['aria-label']==='Limpar Província').props.onClick();h.render();
assert.deepEqual(h.chosen,[undefined]);assert.equal(h.input().props.value,'');
const disabled=harness({disabled:true});assert.equal(disabled.input().props.disabled,true);
assert.equal(disabled.find(node=>node.props?.role==='listbox'),undefined);
});