import { test } from 'node:test'; import assert from 'node:assert/strict'; import { build } from 'esbuild'; import { fileURLToPath } from 'node:url'; import { createRequire } from 'node:module'; import { readFileSync } from 'node:fs'; const root=fileURLToPath(new URL('..',import.meta.url)); const result=await build({stdin:{contents:`import React from 'react'; import {renderToStaticMarkup} from 'react-dom/server'; import Panel from './client/src/components/FirPanel'; import {firTranslate} from './client/src/lib/firLocale'; import {FirRoomDetailsBody} from './client/src/components/FirRoomDetails'; import {firImageUrl} from './client/src/lib/fir'; export {firTranslate,firImageUrl}; export const renderDetails=(room)=>renderToStaticMarkup(React.createElement(FirRoomDetailsBody,{room,language:0})); export const render=()=>renderToStaticMarkup(React.createElement(Panel));`,resolveDir:root},bundle:true,write:false,jsx:'automatic',format:'cjs',platform:'node',alias:{'@':root+'/client/src'},define:{'import.meta.env.VITE_FIR_API_BASE':'"/fir-library"'},plugins:[{name:'device-fixture',setup(b){b.onLoad({filter:/contexts\/DeviceContext\.tsx$/},()=>({contents:'export const useDevice=()=>globalThis.__firDevice;',loader:'js'}));}}]}); const module={exports:{}};new Function('require','module','exports',result.outputFiles[0].text)(createRequire(import.meta.url),module,module.exports); const {render,firTranslate}=module.exports; test('FIR off shows only heading and switch, no form or descriptions',()=>{ globalThis.__firDevice={ip:'test',api:{},isConnected:true,isDemoMode:false,deviceState:{language:0,fir_enable:0}}; const html=render();assert.match(html,/FIR/);assert.doesNotMatch(html,/{ for(const [language,source,upload] of [[0,'Data source','Confirm and upload both channels'],[2,'数据来源','确定并上传双耳数据'],[1,'資料來源','確認並上傳雙耳資料']]) { globalThis.__firDevice={ip:'test',api:{},isConnected:true,isDemoMode:false,deviceState:{language,fir_enable:1}}; const html=render();assert.ok(html.includes(source));assert.ok(html.includes(upload));assert.match(html,/
{ const packs=['en','zh','zh-HK'].map(lang=>JSON.parse(readFileSync(root+'/client/src/locales/data-'+lang+'.json')).fir); for(const pack of packs) {assert.deepEqual(Object.keys(pack).sort(),Object.keys(packs[0]).sort());for(const key of Object.keys(pack))assert.deepEqual((pack[key].match(/\{\w+\}/g)||[]).sort(),(packs[0][key].match(/\{\w+\}/g)||[]).sort());} assert.equal(firTranslate(0,'finite',{index:3}),'Coefficient 3 is not a finite float32 value.'); assert.equal(firTranslate(2,'libraryError',{status:404}),'FIR 文件库请求失败:HTTP 404'); assert.equal(firTranslate(1,'mismatch'),'左右耳抽頭數必須一致'); }); test('room SVG uses configured proxy or remote API base and preserves cache digest',()=>{ const {firImageUrl,renderDetails}=module.exports; assert.equal(firImageUrl('/api/firs/12/image?v=abc','/fir-library'),'/fir-library/firs/12/image?v=abc'); assert.equal(firImageUrl('/api/rooms/R01/image?v=abc','https://library.example/api/'),'https://library.example/api/rooms/R01/image?v=abc'); assert.equal(firImageUrl('javascript:alert(1)','/fir-library'),null); const room={room_id:'R01',label:'Room One',sample_rate:48000,taps:8192,metadata:{},measurement:{azimuth:30,elevation:0},image_url:'/api/firs/12/image?v=abc'}; const html=renderDetails(room); assert.match(html,/]+src="\/fir-library\/firs\/12\/image\?v=abc"/); assert.match(html,/Open full-size SVG/);assert.doesNotMatch(html,/