顺序是刻意的。前端一行测试都没有,直接挪代码挪坏了 bun test 不会红,所以先把纯逻辑 抽到能被测试的位置并补上用例,最后才动组件。测试从 37 条增加到 77 条。 抽出来的四块: - shared/outbound-chain.ts 「这个端口现在走哪条线」的链路解析,带防环,9 条测试 - web/delay-test.ts 延迟测试失败时说什么,6 个分支原本一条测试都没有 - web/runtime.ts 运行时状态的模块级单例,照 prefs.ts 已有的模式 - web/components/InboundList.vue 入站列表 出站的文本原本散成四份(读一份、显示一份、写回一份、表单又抄一份),加一种出站模式 要同时改四处,漏一个就是显示与写回不一致。合并成 OUTBOUND_PRESETS 一张表。 给认证和透传白名单补了 20 条测试。两者都是安全边界、都是纯函数、都不需要内核在线, 之前却只靠需要活内核的冒烟脚本间接覆盖。其中「形似但不是健康检查的路径」几条确认了 正则没写松。 另外:配置快照不再把整份文件原文下发(前端从不读,白白让响应体积翻倍); yaml-cosmetics 的测试改走生产路径,之前它自己拼了一遍三步流程,落盘链路漏掉其中一步 测试照样会绿。
66 lines
2.5 KiB
TypeScript
66 lines
2.5 KiB
TypeScript
import { describe, expect, it } from 'bun:test'
|
|
import { lastSwitchableGroup, resolveChain } from './outbound-chain.ts'
|
|
import type { RuntimeNode } from './outbound-chain.ts'
|
|
|
|
/** 仿照真实那台机器:PROXY 手动选,选中了自动测速的 AUTO,AUTO 挑了一条订阅线路。 */
|
|
const runtime: Record<string, RuntimeNode> = {
|
|
PROXY: { now: 'AUTO', all: ['AUTO', 'DIRECT'] },
|
|
AUTO: { now: '[vless]Gomami', all: ['[vmess]DMIT', '[vless]Gomami'] },
|
|
'[vless]Gomami': {},
|
|
'[vmess]DMIT': {},
|
|
DIRECT: {},
|
|
}
|
|
|
|
describe('解析流量最终走到哪条线', () => {
|
|
it('一路跟着当前选中走到底', () => {
|
|
expect(resolveChain(runtime, 'PROXY')).toEqual(['PROXY', 'AUTO', '[vless]Gomami'])
|
|
})
|
|
|
|
it('起点就是线路时链条只有它自己', () => {
|
|
expect(resolveChain(runtime, '[vless]Gomami')).toEqual(['[vless]Gomami'])
|
|
})
|
|
|
|
it('没有落脚点时是空链条', () => {
|
|
expect(resolveChain(runtime, null)).toEqual([])
|
|
})
|
|
|
|
it('落脚在一个内核不认识的名字上时也只返回它自己', () => {
|
|
// 配置引用了一个不存在的出站时会走到这里,界面要能显示而不是崩掉
|
|
expect(resolveChain(runtime, '不存在的组')).toEqual(['不存在的组'])
|
|
})
|
|
|
|
it('策略组互相引用成环时停下来,不会转死', () => {
|
|
const looped: Record<string, RuntimeNode> = {
|
|
A: { now: 'B', all: ['B'] },
|
|
B: { now: 'A', all: ['A'] },
|
|
}
|
|
expect(resolveChain(looped, 'A')).toEqual(['A', 'B'])
|
|
})
|
|
|
|
it('组选中了自己时也停得下来', () => {
|
|
expect(resolveChain({ A: { now: 'A', all: ['A'] } }, 'A')).toEqual(['A'])
|
|
})
|
|
})
|
|
|
|
describe('找出用户能换选中的那一层', () => {
|
|
it('取链条上最靠近线路的那个策略组', () => {
|
|
// 换 AUTO 的选中才是「换线路」;换 PROXY 换的是「走哪套策略」
|
|
const chain = resolveChain(runtime, 'PROXY')
|
|
expect(lastSwitchableGroup(runtime, chain)).toEqual({
|
|
group: 'AUTO',
|
|
members: ['[vmess]DMIT', '[vless]Gomami'],
|
|
now: '[vless]Gomami',
|
|
})
|
|
})
|
|
|
|
it('链条上一个策略组都没有时返回空', () => {
|
|
expect(lastSwitchableGroup(runtime, ['[vless]Gomami'])).toBeNull()
|
|
expect(lastSwitchableGroup(runtime, [])).toBeNull()
|
|
})
|
|
|
|
it('组存在但成员是空的,不算可切换', () => {
|
|
// 筛选条件没匹配到任何线路时会出现这种组,给出一个点不动的列表只会让人困惑
|
|
expect(lastSwitchableGroup({ 空组: { all: [], now: '' } }, ['空组'])).toBeNull()
|
|
})
|
|
})
|