feat: add props system and refactor asset library architecture
This commit is contained in:
129
tests/unit/assets/mappers.test.ts
Normal file
129
tests/unit/assets/mappers.test.ts
Normal file
@@ -0,0 +1,129 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { mapGlobalVoiceToAsset, mapProjectCharacterToAsset, mapProjectPropToAsset } from '@/lib/assets/mappers'
|
||||
import { groupAssetsByKind } from '@/lib/assets/grouping'
|
||||
|
||||
describe('asset mappers', () => {
|
||||
it('maps project characters into the unified character asset contract', () => {
|
||||
const asset = mapProjectCharacterToAsset({
|
||||
id: 'character-1',
|
||||
name: '林夏',
|
||||
introduction: '主角',
|
||||
voiceType: 'custom',
|
||||
voiceId: 'voice-1',
|
||||
customVoiceUrl: 'https://example.com/voice.mp3',
|
||||
media: null,
|
||||
profileConfirmed: true,
|
||||
appearances: [
|
||||
{
|
||||
id: 'appearance-1',
|
||||
appearanceIndex: 0,
|
||||
changeReason: '初始形象',
|
||||
description: '短发,风衣',
|
||||
imageUrl: 'https://example.com/char.jpg',
|
||||
media: null,
|
||||
imageUrls: ['https://example.com/char.jpg'],
|
||||
imageMedias: [],
|
||||
selectedIndex: 0,
|
||||
previousImageUrl: null,
|
||||
previousMedia: null,
|
||||
previousImageUrls: [],
|
||||
previousImageMedias: [],
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
expect(asset).toEqual(expect.objectContaining({
|
||||
id: 'character-1',
|
||||
scope: 'project',
|
||||
kind: 'character',
|
||||
introduction: '主角',
|
||||
profileConfirmed: true,
|
||||
voice: expect.objectContaining({
|
||||
voiceType: 'custom',
|
||||
voiceId: 'voice-1',
|
||||
}),
|
||||
}))
|
||||
expect(asset.variants[0]).toEqual(expect.objectContaining({
|
||||
id: 'appearance-1',
|
||||
index: 0,
|
||||
label: '初始形象',
|
||||
}))
|
||||
})
|
||||
|
||||
it('maps global voices into the unified audio asset contract', () => {
|
||||
const asset = mapGlobalVoiceToAsset({
|
||||
id: 'voice-1',
|
||||
name: '旁白',
|
||||
description: '低沉稳重',
|
||||
voiceId: 'voice-provider-1',
|
||||
voiceType: 'designed',
|
||||
customVoiceUrl: 'https://example.com/voice.mp3',
|
||||
media: null,
|
||||
voicePrompt: '低沉稳重',
|
||||
gender: 'male',
|
||||
language: 'zh',
|
||||
folderId: 'folder-1',
|
||||
})
|
||||
|
||||
expect(asset).toEqual(expect.objectContaining({
|
||||
id: 'voice-1',
|
||||
scope: 'global',
|
||||
kind: 'voice',
|
||||
voiceMeta: expect.objectContaining({
|
||||
voiceType: 'designed',
|
||||
gender: 'male',
|
||||
language: 'zh',
|
||||
}),
|
||||
}))
|
||||
})
|
||||
|
||||
it('maps project props into the unified visual asset contract and groups them by kind', () => {
|
||||
const propAsset = mapProjectPropToAsset({
|
||||
id: 'prop-1',
|
||||
name: '青铜匕首',
|
||||
summary: '古旧短刃,雕纹手柄',
|
||||
images: [
|
||||
{
|
||||
id: 'prop-image-1',
|
||||
imageIndex: 0,
|
||||
description: '古旧短刃,雕纹手柄',
|
||||
imageUrl: 'https://example.com/prop.jpg',
|
||||
media: null,
|
||||
previousImageUrl: null,
|
||||
previousMedia: null,
|
||||
isSelected: true,
|
||||
},
|
||||
],
|
||||
})
|
||||
const voiceAsset = mapGlobalVoiceToAsset({
|
||||
id: 'voice-1',
|
||||
name: '旁白',
|
||||
description: '低沉稳重',
|
||||
voiceId: 'voice-provider-1',
|
||||
voiceType: 'designed',
|
||||
customVoiceUrl: 'https://example.com/voice.mp3',
|
||||
media: null,
|
||||
voicePrompt: '低沉稳重',
|
||||
gender: 'male',
|
||||
language: 'zh',
|
||||
folderId: 'folder-1',
|
||||
})
|
||||
|
||||
expect(propAsset).toEqual(expect.objectContaining({
|
||||
id: 'prop-1',
|
||||
scope: 'project',
|
||||
kind: 'prop',
|
||||
summary: '古旧短刃,雕纹手柄',
|
||||
selectedVariantId: 'prop-image-1',
|
||||
}))
|
||||
expect(propAsset.variants[0]).toEqual(expect.objectContaining({
|
||||
id: 'prop-image-1',
|
||||
index: 0,
|
||||
description: '古旧短刃,雕纹手柄',
|
||||
}))
|
||||
|
||||
const groups = groupAssetsByKind([propAsset, voiceAsset])
|
||||
expect(groups.prop.map((asset) => asset.id)).toEqual(['prop-1'])
|
||||
expect(groups.voice.map((asset) => asset.id)).toEqual(['voice-1'])
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user