55 lines
5.4 KiB
JavaScript
55 lines
5.4 KiB
JavaScript
import {test} from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import {readFile} from 'node:fs/promises';
|
|
import ts from 'typescript';
|
|
|
|
async function moduleUrl(file,replace=code=>code){
|
|
const code=ts.transpileModule(await readFile(new URL(file,import.meta.url),'utf8'),{compilerOptions:{target:ts.ScriptTarget.ES2022,module:ts.ModuleKind.ESNext}}).outputText;
|
|
return 'data:text/javascript;base64,'+Buffer.from(replace(code)).toString('base64');
|
|
}
|
|
const routing=await moduleUrl('../src/lib/routing.ts'),protocol=await moduleUrl('../src/lib/api/protocol.ts');
|
|
const {navigationEntries,navigationIsActive,mobileNavigationEntries,withoutRemovedNavigation}=await import(await moduleUrl('../src/lib/site-navigation.ts',code=>code.replace("'./api/protocol'",JSON.stringify(protocol)).replace("'./routing'",JSON.stringify(routing))));
|
|
const item=(id,name,urlValue,extra={})=>({id,name,urlValue,categoryType:1,...extra});
|
|
|
|
test('API order, labels, icons and nested destinations are preserved while footer and removed video entries stay absent',()=>{
|
|
const entries=navigationEntries({categoryList:[null,item(20,'精选','/topics/'),item(21,'目录','',{categoryType:2,translationList:[{id:22,name:'第二页',urlValue:'/shorts/page/2/'},null]}),item(23,'更多精彩','/shorts/',{icon:'/assets/custom.webp'}),item(24,'页脚','/info/about-us/',{categoryType:3}),item(25,'剧集','/series/'),item(26,'电影','/video/123/')]});
|
|
assert.deepEqual(entries.map(entry=>entry.name),['精选','目录','更多精彩']);assert.equal(entries[0].href,'/topics/');assert.equal(entries[1].children[0].href,'/shorts/page/2/');assert.equal(entries[2].icon,'/assets/custom.webp');
|
|
assert.deepEqual(mobileNavigationEntries(entries).map(entry=>entry.name),['精选','第二页','更多精彩']);
|
|
for(const categoryList of [null,[],{},'bad',[null]])assert.deepEqual(navigationEntries({categoryList}),[]);
|
|
});
|
|
|
|
test('known API aliases and empty system entries generate native destinations directly without redirects',()=>{
|
|
const entries=navigationEntries({categoryList:[item(1,'首页',''),item(2,'排行','/hot'),item(3,'回家的路',''),item(4,'福利应用',''),item(5,'名字由后台决定','/shorts?sort=2'),item(6,'未知空地址','')]});
|
|
assert.deepEqual(entries.map(entry=>entry.href),['/','/rank/hot/','/home-road/','/shorts/?sort=2']);
|
|
});
|
|
|
|
test('backend navigation entries for the removed welfare app directory are filtered out',()=>{
|
|
const entries=navigationEntries({categoryList:[item(1,'短剧','/shorts/'),item(2,'应用','/apps/'),item(3,'应用二','/application'),item(4,'福利应用','https://drama.test/apps/'),item(5,'福利应用','/topics/'),item(6,'目录','',{categoryType:2,translationList:[{id:7,name:'应用',urlValue:'/apps/'},{id:8,name:'专题',urlValue:'/topics/'}]})]},'https://drama.test');
|
|
assert.deepEqual(entries.map(entry=>entry.name),['短剧','目录']);
|
|
assert.deepEqual(entries[1].children.map(entry=>entry.href),['/topics/']);
|
|
assert.ok(!JSON.stringify(entries).includes('/apps'));
|
|
});
|
|
|
|
test('links reject executable addresses, credentials and removed routes, and keep external URLs external',()=>{
|
|
const entries=navigationEntries({categoryList:[item(1,'外部','https://example.net/path'),item(2,'本站','https://drama.test/shorts'),...['javascript:alert(1)','data:text/html,x','https://user:pass@example.net/','/\\example.net','/video/7/','/series','/shorts/#bad'].map((url,index)=>item(10+index,'无效',url))]},'https://drama.test');
|
|
assert.equal(entries.length,2);assert.equal(entries[0].external,true);assert.equal(entries[1].external,false);assert.equal(entries[1].href,'/shorts/');
|
|
});
|
|
|
|
test('active navigation follows configured destinations, independent pages, pagination and query filters',()=>{
|
|
assert.equal(navigationIsActive('/','/'),true);assert.equal(navigationIsActive('/','/shorts/'),false);
|
|
assert.equal(navigationIsActive('/shorts/','/shorts/page/3/'),true);
|
|
assert.equal(navigationIsActive('/shorts/','/detail/7/','top'),false);assert.equal(navigationIsActive('/shorts/','/detail/7/','sidebar'),true);
|
|
assert.equal(navigationIsActive('/topics/','/topics/7/','top'),false);assert.equal(navigationIsActive('/topics/7/','/topics/7/page/2/'),true);assert.equal(navigationIsActive('/topics/7/','/topics/8/'),false);
|
|
for(const slug of ['hot','new','follow'])assert.equal(navigationIsActive('/rank/hot/',`/rank/${slug}/page/2/`),true);
|
|
assert.equal(navigationIsActive('/rank/new/','/rank/follow/'),false);
|
|
assert.equal(navigationIsActive('/shorts/?sort=2','/shorts/page/2/?sort=2&campaign=test'),true);assert.equal(navigationIsActive('/shorts/?sort=2','/shorts/?sort=1'),false);
|
|
assert.equal(navigationIsActive('https://example.net/shorts/','/shorts/'),false);assert.equal(navigationIsActive('/series/','/series/'),false);
|
|
});
|
|
|
|
test('the serialized backend navigation payload no longer carries welfare-app entries',()=>{
|
|
const data=withoutRemovedNavigation({categoryList:[{id:1,name:'短剧',urlValue:'/shorts/',categoryType:1},{id:2,name:'福利应用',urlValue:'',categoryType:1},{id:3,name:'应用',urlValue:'https://drama.test/apps/',categoryType:1},{id:4,name:'目录',urlValue:'',categoryType:2,translationList:[{id:5,name:'应用',urlValue:'/application'},{id:6,name:'专题',urlValue:'/topics/'}]}]});
|
|
assert.deepEqual(data.categoryList.map(item=>item.id),[1,4]);
|
|
assert.deepEqual(data.categoryList[1].translationList.map(item=>item.id),[6]);
|
|
assert.deepEqual(withoutRemovedNavigation(null).categoryList,[]);
|
|
});
|