-
-
Notifications
You must be signed in to change notification settings - Fork 130
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
bcec368
commit 1394c8a
Showing
1 changed file
with
201 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,201 @@ | ||
import React from "react"; | ||
import { expect } from "@jest/globals"; | ||
import { | ||
startVoiceRecording, | ||
stopVoiceRecording, | ||
syncVoiceWithChatInput, | ||
} from "../../src/services/VoiceService"; | ||
import { Settings } from "../../src/types/Settings"; | ||
import { RefObject } from "react"; | ||
|
||
describe("VoiceService", () => { | ||
let mockInputRef: RefObject<HTMLInputElement | null>; | ||
|
||
beforeEach(() => { | ||
jest.clearAllMocks(); | ||
|
||
mockInputRef = { current: document.createElement("input") }; | ||
|
||
// Mock SpeechRecognition | ||
Object.defineProperty(window, "SpeechRecognition", { | ||
configurable: true, | ||
value: jest.fn().mockImplementation(() => ({ | ||
start: jest.fn(), | ||
stop: jest.fn(), | ||
onresult: jest.fn(), | ||
onend: jest.fn(), | ||
})), | ||
}); | ||
|
||
// Mock navigator.mediaDevices | ||
Object.defineProperty(navigator, "mediaDevices", { | ||
configurable: true, | ||
value: { | ||
getUserMedia: jest.fn(), | ||
}, | ||
}); | ||
}); | ||
|
||
afterEach(() => { | ||
jest.restoreAllMocks(); | ||
}); | ||
|
||
it("starts voice recording with SpeechRecognition", () => { | ||
const mockToggleVoice = jest.fn(); | ||
const mockTriggerSendVoiceInput = jest.fn(); | ||
const mockSetTextAreaValue = jest.fn(); | ||
const mockSetInputLength = jest.fn(); | ||
const mockAudioChunksRef: RefObject<BlobPart[]> = { current: [] }; | ||
|
||
const mockSettings: Settings = { | ||
voice: { | ||
sendAsAudio: false, | ||
language: "en-US", | ||
timeoutPeriod: 5000, | ||
autoSendPeriod: 3000, | ||
autoSendDisabled: false, | ||
}, | ||
}; | ||
|
||
startVoiceRecording( | ||
mockSettings, | ||
mockToggleVoice, | ||
mockTriggerSendVoiceInput, | ||
mockSetTextAreaValue, | ||
mockSetInputLength, | ||
mockAudioChunksRef, | ||
mockInputRef | ||
); | ||
|
||
expect(mockToggleVoice).not.toHaveBeenCalled(); | ||
}); | ||
|
||
it("stops voice recording without errors", () => { | ||
stopVoiceRecording(); | ||
|
||
expect(true).toBe(true); // Dummy check | ||
}); | ||
|
||
it("syncs voice recording with chat input", () => { | ||
const mockSettings: Settings = { | ||
voice: { disabled: false }, | ||
chatInput: { blockSpam: true }, | ||
}; | ||
|
||
syncVoiceWithChatInput(true, mockSettings); | ||
expect(true).toBe(true); // Dummy check | ||
}); | ||
|
||
it("handles error during SpeechRecognition initialization gracefully", () => { | ||
// Simulate SpeechRecognition not being supported | ||
Object.defineProperty(window, "SpeechRecognition", { | ||
configurable: true, | ||
value: jest.fn(() => { | ||
throw new Error("SpeechRecognition not supported"); | ||
}), | ||
}); | ||
|
||
const mockToggleVoice = jest.fn(); | ||
const mockTriggerSendVoiceInput = jest.fn(); | ||
const mockSetTextAreaValue = jest.fn(); | ||
const mockSetInputLength = jest.fn(); | ||
const mockAudioChunksRef: RefObject<BlobPart[]> = { current: [] }; | ||
|
||
const mockSettings: Settings = { | ||
voice: { | ||
sendAsAudio: false, | ||
language: "en-US", | ||
timeoutPeriod: 5000, | ||
autoSendPeriod: 3000, | ||
}, | ||
}; | ||
|
||
expect(() => { | ||
startVoiceRecording( | ||
mockSettings, | ||
mockToggleVoice, | ||
mockTriggerSendVoiceInput, | ||
mockSetTextAreaValue, | ||
mockSetInputLength, | ||
mockAudioChunksRef, | ||
mockInputRef | ||
); | ||
}).not.toThrow(); | ||
}); | ||
|
||
it("does not start MediaRecorder if microphone permissions are denied", async () => { | ||
// Mock getUserMedia to reject the promise | ||
jest.spyOn(navigator.mediaDevices, "getUserMedia").mockRejectedValueOnce( | ||
new Error("Permission denied") | ||
); | ||
|
||
const mockToggleVoice = jest.fn(); | ||
const mockTriggerSendVoiceInput = jest.fn(); | ||
const mockSetTextAreaValue = jest.fn(); | ||
const mockSetInputLength = jest.fn(); | ||
const mockAudioChunksRef: RefObject<BlobPart[]> = { current: [] }; | ||
|
||
const mockSettings: Settings = { | ||
voice: { sendAsAudio: true }, | ||
}; | ||
|
||
try { | ||
await startVoiceRecording( | ||
mockSettings, | ||
mockToggleVoice, | ||
mockTriggerSendVoiceInput, | ||
mockSetTextAreaValue, | ||
mockSetInputLength, | ||
mockAudioChunksRef, | ||
mockInputRef | ||
); | ||
} catch (error) { | ||
if (error instanceof Error) { | ||
expect(error.message).toBe("Permission denied"); | ||
} else { | ||
throw error; // Re-throw if it's not an Error instance | ||
} | ||
} | ||
}); | ||
|
||
it("handles timeout and auto-send behavior", () => { | ||
jest.useFakeTimers(); | ||
|
||
const mockToggleVoice = jest.fn(); | ||
const mockTriggerSendVoiceInput = jest.fn(); | ||
const mockSetTextAreaValue = jest.fn(); | ||
const mockSetInputLength = jest.fn(); | ||
const mockAudioChunksRef: RefObject<BlobPart[]> = { current: [] }; | ||
|
||
const mockSettings: Settings = { | ||
voice: { | ||
sendAsAudio: false, | ||
timeoutPeriod: 5000, | ||
autoSendPeriod: 3000, | ||
}, | ||
}; | ||
|
||
const timeoutPeriod = mockSettings.voice?.timeoutPeriod ?? 0; | ||
const autoSendPeriod = mockSettings.voice?.autoSendPeriod ?? 0; | ||
|
||
startVoiceRecording( | ||
mockSettings, | ||
mockToggleVoice, | ||
mockTriggerSendVoiceInput, | ||
mockSetTextAreaValue, | ||
mockSetInputLength, | ||
mockAudioChunksRef, | ||
mockInputRef | ||
); | ||
|
||
// Simulate timeout | ||
jest.advanceTimersByTime(timeoutPeriod); | ||
expect(mockToggleVoice).toHaveBeenCalled(); | ||
|
||
// Simulate auto-send period | ||
jest.advanceTimersByTime(autoSendPeriod); | ||
expect(mockTriggerSendVoiceInput).toHaveBeenCalled(); | ||
|
||
jest.useRealTimers(); | ||
}); | ||
}); |