merge(main): 解决 usage 展示与生命周期同步冲突

This commit is contained in:
MMEXA
2026-07-18 05:38:38 +08:00
111 changed files with 8984 additions and 1715 deletions
@@ -0,0 +1,38 @@
import { describe, expect, it } from 'vitest'
import { createSSRApp, h } from 'vue'
import { renderToString } from '@vue/server-renderer'
import type { ProviderWithEndpointsSummary } from '@/api/endpoints'
import ModelMappingTab from '../provider-tabs/ModelMappingTab.vue'
const provider = {
id: 'provider-demo',
name: 'Demo Provider',
provider_type: 'custom',
is_active: true,
active_keys: 0,
api_formats: [],
} as ProviderWithEndpointsSummary
describe('ModelMappingTab response contracts', () => {
it('keeps the module visible when a legacy or malformed preview reaches the component', async () => {
const app = createSSRApp({
render: () => h(ModelMappingTab, {
provider,
models: [],
endpoints: [],
providerKeys: [],
mappingPreview: {
message: '演示模式:该接口暂未模拟',
demo_mode: true,
},
loading: false,
}),
})
const html = await renderToString(app)
expect(html).toContain('模型映射')
expect(html).toContain('暂无模型映射')
})
})
@@ -0,0 +1,32 @@
import { readFileSync } from 'node:fs'
import { resolve } from 'node:path'
import { describe, expect, it } from 'vitest'
const source = readFileSync(
resolve(process.cwd(), 'src/features/providers/components/ProviderDetailDrawer.vue'),
'utf8',
)
describe('ProviderDetailDrawer loading priorities', () => {
it('loads mapping preview after first-screen provider data', () => {
const openWatcher = source
.split('// 合并监听 providerId 和 open')[1]
?.split('} else if (!newOpen && oldOpen)')[0]
expect(openWatcher).toBeTruthy()
expect(openWatcher).toContain('const endpointsPromise = loadEndpoints()')
expect(openWatcher).toContain('endpointsPromise.then(() => {')
expect(openWatcher).toContain('if (!props.open || props.providerId !== newId) return')
expect(openWatcher).toContain('void loadMappingPreview()')
const beforeEndpoints = openWatcher?.split('const endpointsPromise = loadEndpoints()')[0]
expect(beforeEndpoints).not.toContain('loadMappingPreview()')
})
it('keeps model and mapping loading states independent', () => {
expect(source).toContain(':loading="loadingProviderModels"')
expect(source).toContain(':loading="loadingProviderMappingPreview"')
expect(source).not.toContain(':loading="loadingProviderModels || loadingProviderKeys"')
expect(source).not.toContain(':loading="loadingProviderEndpoints || loadingProviderKeys || loadingProviderModels || loadingProviderMappingPreview"')
})
})