Files
2026-10-30 17:40:13 +08:00

43 lines
4.1 KiB
JavaScript

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,/<fieldset|<select|<p|<button/);
});
test('enabled form follows English, Simplified Chinese and Traditional Chinese',()=>{
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,/<fieldset/);
assert.doesNotMatch(html,/查看房间|刷新房间|float32|Disable FIR and confirm|Sample rate/);
}
});
test('all supported FIR locales have matching keys and substitution tokens',()=>{
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,/<img[^>]+src="\/fir-library\/firs\/12\/image\?v=abc"/);
assert.match(html,/Open full-size SVG/);assert.doesNotMatch(html,/<details|30°/);
assert.ok(!html.includes(firTranslate(0,'detailMeasurement')));assert.ok(!html.includes(firTranslate(0,'detailMore')));
const fallback=renderDetails({...room,image_url:null});
assert.doesNotMatch(fallback,/<img|<details/);assert.ok(fallback.includes(firTranslate(0,'detailDimensions')));
});