Files
waooplus/tests/unit/novel-promotion/use-tts-generation.test.ts
2026-03-08 17:10:06 +08:00

113 lines
3.2 KiB
TypeScript

import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
const {
useStateMock,
logErrorMock,
refreshAssetsMock,
updateVoiceSettingsMutateAsyncMock,
saveDesignedVoiceMutateAsyncMock,
setVoiceDesignCharacterMock,
} = vi.hoisted(() => ({
useStateMock: vi.fn(),
logErrorMock: vi.fn(),
refreshAssetsMock: vi.fn(),
updateVoiceSettingsMutateAsyncMock: vi.fn(),
saveDesignedVoiceMutateAsyncMock: vi.fn(),
setVoiceDesignCharacterMock: vi.fn(),
}))
vi.mock('react', async () => {
const actual = await vi.importActual<typeof import('react')>('react')
return {
...actual,
useState: useStateMock,
}
})
vi.mock('next-intl', () => ({
useTranslations: () => (key: string, values?: Record<string, unknown>) => {
if (key === 'tts.voiceDesignSaved') {
return `voice saved:${String(values?.name ?? '')}`
}
if (key === 'tts.saveVoiceDesignFailed') {
return `save failed:${String(values?.error ?? '')}`
}
if (key === 'common.unknownError') {
return 'unknown error'
}
return key
},
}))
vi.mock('@/lib/logging/core', () => ({
logError: (...args: unknown[]) => logErrorMock(...args),
}))
vi.mock('@/lib/query/hooks', () => ({
useProjectAssets: () => ({
data: {
characters: [{
id: 'character-1',
name: 'Hero',
customVoiceUrl: null,
}],
},
}),
useRefreshProjectAssets: () => refreshAssetsMock,
useUpdateProjectCharacterVoiceSettings: () => ({
mutateAsync: updateVoiceSettingsMutateAsyncMock,
}),
useSaveProjectDesignedVoice: () => ({
mutateAsync: saveDesignedVoiceMutateAsyncMock,
}),
}))
import { useTTSGeneration } from '@/app/[locale]/workspace/[projectId]/modes/novel-promotion/components/assets/hooks/useTTSGeneration'
describe('useTTSGeneration', () => {
const originalAlert = globalThis.alert
beforeEach(() => {
useStateMock.mockReset()
logErrorMock.mockReset()
refreshAssetsMock.mockReset()
updateVoiceSettingsMutateAsyncMock.mockReset()
saveDesignedVoiceMutateAsyncMock.mockReset()
setVoiceDesignCharacterMock.mockReset()
saveDesignedVoiceMutateAsyncMock.mockResolvedValue({
success: true,
audioUrl: 'https://signed.example.com/audio.wav',
})
globalThis.alert = vi.fn()
useStateMock.mockReturnValue([
{
id: 'character-1',
name: 'Hero',
hasExistingVoice: false,
},
setVoiceDesignCharacterMock,
])
})
afterEach(() => {
globalThis.alert = originalAlert
})
it('does not send a second voice update request after designed voice save succeeds', async () => {
const hook = useTTSGeneration({ projectId: 'project-1' })
await hook.handleVoiceDesignSave('voice-1', 'base64-audio')
expect(saveDesignedVoiceMutateAsyncMock).toHaveBeenCalledTimes(1)
expect(saveDesignedVoiceMutateAsyncMock).toHaveBeenCalledWith({
characterId: 'character-1',
voiceId: 'voice-1',
audioBase64: 'base64-audio',
})
expect(updateVoiceSettingsMutateAsyncMock).not.toHaveBeenCalled()
expect(refreshAssetsMock).toHaveBeenCalledTimes(1)
expect(globalThis.alert).toHaveBeenCalledWith('voice saved:Hero')
expect(setVoiceDesignCharacterMock).toHaveBeenCalledWith(null)
})
})