const test=require('node:test'),assert=require('node:assert/strict'),fs=require('node:fs'); const read=path=>fs.readFileSync(path,'utf8'); test('Vue production entry uses local hashed assets and precompiled templates',()=>{ const html=read('web/ui/index.html'); assert.match(html,/type="module"[^>]+src="\/ui\/assets\/index-/); assert.match(html,/rel="stylesheet"[^>]+href="\/ui\/assets\/index-/); assert.doesNotMatch(html,/https?:\/\/|unsafe-eval/); const config=read('frontend/package.json');assert.match(config,/"vue"/);assert.match(config,/"bootstrap"/); }); test('Vue compatibility boundary preserves unique static DOM identities',()=>{ const source=require('./test-support/ui-source')(); const ids=[...source.matchAll(/\sid="([\w-]+)"/g)].map(m=>m[1]); assert.equal(ids.length,new Set(ids).size); for(const id of ['auth-form','device-form','household-list','asset-list','device-topology','device-detail','live-grid','journal-form'])assert.ok(ids.includes(id),id); const app=read('web/app.js');assert.match(app,/window\.ZhaoVue\?\.clear\(\)/);assert.match(app,/window\.ZhaoVue\?\.publish\?\.\(\)/); const load=read('frontend/src/compat/load.js');assert.match(load,/await new Promise/);assert.match(load,/await window\.ZhaoVue.boot/); }); test('network widget rejects stale responses and stops timers on unmount',()=>{ const component=read('frontend/src/components/NetworkStatus.vue'); assert.match(component,/current===generation/);assert.match(component,/onUnmounted/);assert.match(component,/clearTimeout\(timer\)/); assert.match(component,/rel="noopener noreferrer"/);assert.match(component,/snapshot.admin/); const routes=read('app.py');assert.match(routes,/self.require_manager\(\); self.answer\(NETWORK.read/); }); test('explicit device detail does not force camera live view',()=>{ const vm=require('node:vm'),source=read('web/steward.js');let shown=''; const context=vm.createContext({ZhaoDevices:{catalog:()=>[{id:'a',source:'camera'}]},state:{cameras:[{}]},toast(){},stopPlayers(){},resetPlayback(){},deviceCameras:()=>[{}],$:()=>({value:''}),showPage:value=>shown=value}); vm.runInContext(source.slice(source.indexOf('function enterDevice('),source.indexOf('function renderSteward(')),context); context.enterDevice('camera','a','device');assert.equal(shown,'device');context.enterDevice('camera','a');assert.equal(shown,'live'); });