mirror of
https://wget.la/https://github.com/Wxw-Gu/WechatExplorer
synced 2026-10-04 03:01:42 +08:00
118 lines
3.8 KiB
TypeScript
118 lines
3.8 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
|
|
const mocks = vi.hoisted(() => ({
|
|
keyGet: vi.fn(),
|
|
keySave: vi.fn(),
|
|
keyClear: vi.fn(),
|
|
loadSettings: vi.fn(),
|
|
updateSettings: vi.fn()
|
|
}))
|
|
|
|
const electronNetFetch = vi.hoisted(() => vi.fn())
|
|
|
|
vi.mock('electron', () => ({
|
|
app: {
|
|
getPath: vi.fn(() => '/tmp/tracememo-test')
|
|
},
|
|
net: {
|
|
fetch: electronNetFetch
|
|
}
|
|
}))
|
|
|
|
vi.mock('../../src/main/ai-provider-key-store', () => ({
|
|
AIProviderKeyStore: class {
|
|
get = mocks.keyGet
|
|
save = mocks.keySave
|
|
clear = mocks.keyClear
|
|
}
|
|
}))
|
|
|
|
vi.mock('../../src/main/services/settings-store', () => ({
|
|
loadSettings: mocks.loadSettings,
|
|
updateSettings: mocks.updateSettings
|
|
}))
|
|
|
|
import { TextToSpeechSettingsService } from '../../src/main/services/text-to-speech-settings-service'
|
|
|
|
describe('TextToSpeechSettingsService', () => {
|
|
beforeEach(() => {
|
|
mocks.keyGet.mockReset().mockReturnValue({
|
|
success: true,
|
|
available: true,
|
|
key: undefined
|
|
})
|
|
mocks.keySave.mockReset().mockReturnValue({ success: true })
|
|
mocks.keyClear.mockReset().mockReturnValue({ success: true })
|
|
mocks.loadSettings.mockReset().mockReturnValue({ ttsSelectedVoiceId: 'demo-warm-female' })
|
|
mocks.updateSettings.mockReset()
|
|
})
|
|
|
|
it('returns an empty dynamic voice list without exposing a missing key', () => {
|
|
const result = new TextToSpeechSettingsService().get()
|
|
expect(result.success).toBe(true)
|
|
expect(result.settings.hasApiKey).toBe(false)
|
|
expect(result.settings.selectedVoiceId).toBe('')
|
|
expect(result.voices).toEqual([])
|
|
})
|
|
|
|
it('stores the key securely and persists the selected voice', () => {
|
|
mocks.keyGet.mockReturnValue({ success: true, available: true, key: 'stored' })
|
|
const result = new TextToSpeechSettingsService().save({
|
|
apiKey: ' fish-key ',
|
|
selectedVoiceId: 'demo-calm-male'
|
|
})
|
|
expect(mocks.keySave).toHaveBeenCalledWith('fish-audio-tts', 'fish-key')
|
|
expect(mocks.updateSettings).toHaveBeenCalledWith({
|
|
ttsSelectedVoiceId: 'demo-calm-male'
|
|
})
|
|
expect(result.settings.hasApiKey).toBe(true)
|
|
})
|
|
|
|
it('persists a remotely loaded voice id without local demo validation', () => {
|
|
const result = new TextToSpeechSettingsService().save({
|
|
selectedVoiceId: 'fish-model-id'
|
|
})
|
|
expect(result.success).toBe(true)
|
|
expect(mocks.updateSettings).toHaveBeenCalledWith({
|
|
ttsSelectedVoiceId: 'fish-model-id'
|
|
})
|
|
})
|
|
|
|
it('uses Electron net.fetch for Fish Audio requests', async () => {
|
|
mocks.keyGet.mockReturnValue({ success: true, available: true, key: 'stored' })
|
|
electronNetFetch.mockResolvedValue({
|
|
ok: true,
|
|
json: vi.fn().mockResolvedValue({ total: 0, items: [], has_more: false })
|
|
})
|
|
|
|
const result = await new TextToSpeechSettingsService().listVoices({ pageSize: 1 })
|
|
|
|
expect(result.success).toBe(true)
|
|
expect(electronNetFetch).toHaveBeenCalledWith(
|
|
expect.stringContaining('https://api.fish.audio/model'),
|
|
expect.objectContaining({
|
|
headers: { Authorization: 'Bearer stored' }
|
|
})
|
|
)
|
|
})
|
|
|
|
it('falls back to Node fetch when Electron transport is unavailable', async () => {
|
|
mocks.keyGet.mockReturnValue({ success: true, available: true, key: 'stored' })
|
|
electronNetFetch.mockRejectedValue(new TypeError('Electron transport unavailable'))
|
|
const nodeFetch = vi.fn().mockResolvedValue({
|
|
ok: true,
|
|
json: vi.fn().mockResolvedValue({ total: 0, items: [], has_more: false })
|
|
})
|
|
vi.stubGlobal('fetch', nodeFetch)
|
|
|
|
const result = await new TextToSpeechSettingsService().listVoices({ pageSize: 1 })
|
|
|
|
expect(result.success).toBe(true)
|
|
expect(nodeFetch).toHaveBeenCalledWith(
|
|
expect.stringContaining('https://api.fish.audio/model'),
|
|
expect.objectContaining({ headers: { Authorization: 'Bearer stored' } })
|
|
)
|
|
vi.unstubAllGlobals()
|
|
})
|
|
})
|