将 vansour/sub2api#1555 的 OpenAI compact 能力建模手工移植到当前 main:账号 级 compact 状态/auto-force_on-force_off 模式、compact-only 模型映射、调度器 tier 分层(已支持 > 未知 > 已知不支持)、管理后台 compact 主动探测,以及对应 i18n/状态徽章。普通 /responses 流量行为不变,无数据库迁移。
151 lines
3.5 KiB
TypeScript
151 lines
3.5 KiB
TypeScript
import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest'
|
|
import { flushPromises, mount } from '@vue/test-utils'
|
|
import { defineComponent } from 'vue'
|
|
import AccountTestModal from '../AccountTestModal.vue'
|
|
|
|
const { getAvailableModelsMock } = vi.hoisted(() => ({
|
|
getAvailableModelsMock: vi.fn()
|
|
}))
|
|
|
|
vi.mock('@/api/admin', () => ({
|
|
adminAPI: {
|
|
accounts: {
|
|
getAvailableModels: getAvailableModelsMock
|
|
}
|
|
}
|
|
}))
|
|
|
|
vi.mock('@/composables/useClipboard', () => ({
|
|
useClipboard: () => ({
|
|
copyToClipboard: vi.fn()
|
|
})
|
|
}))
|
|
|
|
vi.mock('vue-i18n', async () => {
|
|
const actual = await vi.importActual<typeof import('vue-i18n')>('vue-i18n')
|
|
return {
|
|
...actual,
|
|
useI18n: () => ({
|
|
t: (key: string) => key
|
|
})
|
|
}
|
|
})
|
|
|
|
const BaseDialogStub = defineComponent({
|
|
name: 'BaseDialog',
|
|
props: { show: { type: Boolean, default: false } },
|
|
template: '<div v-if="show"><slot /><slot name="footer" /></div>'
|
|
})
|
|
|
|
const SelectStub = defineComponent({
|
|
name: 'SelectStub',
|
|
props: {
|
|
modelValue: { type: [String, Number, Boolean, null], default: '' },
|
|
options: { type: Array, default: () => [] },
|
|
valueKey: { type: String, default: 'value' },
|
|
labelKey: { type: String, default: 'label' }
|
|
},
|
|
emits: ['update:modelValue'],
|
|
template: `
|
|
<select
|
|
v-bind="$attrs"
|
|
:value="modelValue"
|
|
@change="$emit('update:modelValue', $event.target.value)"
|
|
>
|
|
<option
|
|
v-for="option in options"
|
|
:key="option[valueKey]"
|
|
:value="option[valueKey]"
|
|
>
|
|
{{ option[labelKey] }}
|
|
</option>
|
|
</select>
|
|
`
|
|
})
|
|
|
|
const TextAreaStub = defineComponent({
|
|
name: 'TextArea',
|
|
props: {
|
|
modelValue: { type: String, default: '' }
|
|
},
|
|
emits: ['update:modelValue'],
|
|
template: `
|
|
<textarea
|
|
v-bind="$attrs"
|
|
:value="modelValue"
|
|
@input="$emit('update:modelValue', $event.target.value)"
|
|
/>
|
|
`
|
|
})
|
|
|
|
function buildAccount() {
|
|
return {
|
|
id: 1,
|
|
name: 'OpenAI OAuth',
|
|
platform: 'openai',
|
|
type: 'oauth',
|
|
status: 'active',
|
|
credentials: {},
|
|
extra: {},
|
|
concurrency: 1,
|
|
priority: 1,
|
|
proxy_id: null,
|
|
auto_pause_on_expired: false
|
|
} as any
|
|
}
|
|
|
|
describe('AccountTestModal', () => {
|
|
const originalFetch = global.fetch
|
|
|
|
beforeEach(() => {
|
|
getAvailableModelsMock.mockReset()
|
|
getAvailableModelsMock.mockResolvedValue([
|
|
{ id: 'gpt-5.4', display_name: 'GPT-5.4' }
|
|
])
|
|
global.fetch = vi.fn().mockResolvedValue({
|
|
ok: true,
|
|
body: {
|
|
getReader: () => ({
|
|
read: vi.fn().mockResolvedValue({ done: true, value: undefined })
|
|
})
|
|
}
|
|
} as any)
|
|
localStorage.setItem('auth_token', 'test-token')
|
|
})
|
|
|
|
afterEach(() => {
|
|
global.fetch = originalFetch
|
|
localStorage.clear()
|
|
})
|
|
|
|
it('posts compact mode for OpenAI compact probe', async () => {
|
|
const wrapper = mount(AccountTestModal, {
|
|
props: {
|
|
show: true,
|
|
account: buildAccount()
|
|
},
|
|
global: {
|
|
stubs: {
|
|
BaseDialog: BaseDialogStub,
|
|
Select: SelectStub,
|
|
TextArea: TextAreaStub,
|
|
Icon: true
|
|
}
|
|
}
|
|
})
|
|
|
|
await flushPromises()
|
|
;(wrapper.vm as any).selectedModelId = 'gpt-5.4'
|
|
;(wrapper.vm as any).testMode = 'compact'
|
|
await (wrapper.vm as any).startTest()
|
|
await flushPromises()
|
|
|
|
expect(global.fetch).toHaveBeenCalledTimes(1)
|
|
const [, options] = (global.fetch as any).mock.calls[0]
|
|
expect(JSON.parse(options.body)).toMatchObject({
|
|
model_id: 'gpt-5.4',
|
|
mode: 'compact'
|
|
})
|
|
})
|
|
})
|