Files
story/firmware/echoear-platform-agent/tests/setup-portal.test.cjs
T

38 lines
3.9 KiB
JavaScript
Raw Normal View History

2026-09-06 17:04:11 +08:00
const {test}=require('node:test');
const assert=require('node:assert/strict');
const fs=require('node:fs');
const vm=require('node:vm');
const html=fs.readFileSync(require('node:path').join(__dirname,'../main/assets/wifi_configuration_ap.html'),'utf8');
const source=html.match(/<script>([\s\S]*?)<\/script>/)[1];
async function page(route){
const elements={};
const element=id=>elements[id]??=( {value:'',disabled:false,textContent:'',style:{},events:{},children:[],addEventListener(t,fn){this.events[t]=fn},appendChild(x){this.children.push(x)},checkValidity(){return true},reportValidity(){}} );
for(const id of ['form','submit','scan','status','networks','ssid','password','device_id','device_secret'])element(id);
elements.ssid.value='Home & Family';elements.password.value='abc&+%=中文';elements.device_id.value='12345678-1234-1234-1234-123456789abc';elements.device_secret.value='x'.repeat(32);
let clock=0,initial=true;const calls=[];
vm.runInNewContext(source,{document:{getElementById:element,createElement:()=>({events:{},addEventListener(t,fn){this.events[t]=fn}})},TextEncoder,AbortController,Date:{now:()=>clock},setTimeout(fn,ms){if(ms===1500){clock+=ms;queueMicrotask(fn)}return 1},clearTimeout(){},fetch:async(path,options)=>{calls.push({path,options});const data=initial&&path==='/setup-status'?(initial=false,{state:'idle'}):await route(path,options);return {ok:!data.error,json:async()=>data}}});
await new Promise(setImmediate);
return {elements,calls,submit:()=>elements.form.events.submit({preventDefault(){}})};
}
test('submit gives immediate feedback and recovers from Wi-Fi failure',async()=>{
let release;const p=await page(async path=>path==='/submit'?await new Promise(r=>release=r):{state:'wifi_failed'});
const pending=p.submit();assert.equal(p.elements.submit.disabled,true);assert.match(p.elements.status.textContent,/正在提交/);
release({state:'connecting'});await pending;assert.equal(p.elements.submit.disabled,false);assert.match(p.elements.status.textContent,/连接失败/);
const payload=JSON.parse(p.calls.find(c=>c.path==='/submit').options.body);assert.equal(payload.password,'abc&+%=中文');assert.equal(payload.ssid,'Home & Family');
});
test('accepted job polls to saved and does not claim platform activation already succeeded',async()=>{
let polls=0;const p=await page(async path=>path==='/submit'?{state:'connecting'}:{state:++polls===1?'connecting':'saved'});
await p.submit();assert.equal(p.elements.submit.disabled,true);assert.match(p.elements.status.textContent,/配置已保存/);assert.match(p.elements.status.textContent,/重启并进行平台激活/);
});
test('server validation error restores retry',async()=>{const p=await page(async()=>({error:'invalid_fields'}));await p.submit();assert.equal(p.elements.submit.disabled,false);assert.match(p.elements.status.textContent,/检查配置/)});
test('lost submit response queries job instead of issuing another submission',async()=>{
const p=await page(async path=>{if(path==='/submit')throw new Error('network lost');return {state:'saved'}});await p.submit();assert.equal(p.calls.filter(c=>c.path==='/submit').length,1);assert.match(p.elements.status.textContent,/配置已保存/);
});
test('unreachable device exits waiting with an honest unknown result',async()=>{
const p=await page(async()=>{throw new Error('offline')});await p.submit();assert.equal(p.elements.submit.disabled,false);assert.match(p.elements.status.textContent,/无法确认结果/);
});
test('invalid form and overlong UTF-8 SSID never submit',async()=>{
const p=await page(async()=>({state:'saved'}));p.elements.form.checkValidity=()=>false;await p.submit();assert.equal(p.calls.filter(c=>c.path==='/submit').length,0);assert.match(p.elements.status.textContent,/完整填写/);
p.elements.form.checkValidity=()=>true;p.elements.ssid.value='中'.repeat(11);await p.submit();assert.equal(p.calls.filter(c=>c.path==='/submit').length,0);assert.match(p.elements.status.textContent,/32字节/);
});