-
-
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 0e9034f
Showing
4 changed files
with
260 additions
and
5 deletions.
There are no files selected for viewing
116 changes: 116 additions & 0 deletions
116
__tests__/components/ChatBotBody/ChatMessagePrompt.test.tsx
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,116 @@ | ||
import React from "react"; | ||
import { render, screen, fireEvent } from "@testing-library/react"; | ||
import "@testing-library/jest-dom"; | ||
import ChatMessagePrompt from "../../../src/components/ChatBotBody/ChatMessagePrompt/ChatMessagePrompt"; | ||
|
||
// Mock contexts | ||
jest.mock("../../../src/context/BotRefsContext", () => ({ | ||
useBotRefsContext: jest.fn(() => ({ | ||
chatBodyRef: { | ||
current: { | ||
scrollTop: 0, | ||
scrollHeight: 1000, | ||
clientHeight: 400, | ||
}, | ||
}, | ||
})), | ||
})); | ||
|
||
const mockSetIsScrolling = jest.fn(); | ||
let unreadCountMock = 0; | ||
let isScrollingMock = false; | ||
|
||
jest.mock("../../../src/context/BotStatesContext", () => ({ | ||
useBotStatesContext: jest.fn(() => ({ | ||
unreadCount: unreadCountMock, | ||
isScrolling: isScrollingMock, | ||
setIsScrolling: mockSetIsScrolling, | ||
})), | ||
})); | ||
|
||
jest.mock("../../../src/context/SettingsContext", () => ({ | ||
useSettingsContext: jest.fn(() => ({ | ||
settings: { | ||
general: { primaryColor: "#000" }, | ||
chatWindow: { | ||
showMessagePrompt: true, | ||
messagePromptText: "Scroll to new messages", | ||
}, | ||
}, | ||
})), | ||
})); | ||
|
||
jest.mock("../../../src/context/StylesContext", () => ({ | ||
useStylesContext: jest.fn(() => ({ | ||
styles: { | ||
chatMessagePromptStyle: { color: "#fff", borderColor: "#ccc" }, | ||
chatMessagePromptHoveredStyle: { color: "#000", borderColor: "#000" }, | ||
}, | ||
})), | ||
})); | ||
|
||
describe("ChatMessagePrompt Component", () => { | ||
beforeEach(() => { | ||
jest.clearAllMocks(); | ||
jest.useFakeTimers(); | ||
}); | ||
|
||
afterEach(() => { | ||
jest.useRealTimers(); | ||
}); | ||
|
||
const renderComponent = () => render(<ChatMessagePrompt />); | ||
|
||
it("renders with the correct message prompt text", () => { | ||
renderComponent(); | ||
const messagePrompt = screen.getByText("Scroll to new messages"); | ||
expect(messagePrompt).toBeInTheDocument(); | ||
}); | ||
|
||
it("applies visible class when conditions are met", () => { | ||
unreadCountMock = 2; | ||
isScrollingMock = true; | ||
|
||
renderComponent(); | ||
const messagePrompt = screen.getByText("Scroll to new messages"); | ||
expect(messagePrompt.parentElement).toHaveClass("rcb-message-prompt-container visible"); | ||
}); | ||
|
||
it("applies hidden class when conditions are not met", () => { | ||
unreadCountMock = 0; | ||
isScrollingMock = false; | ||
|
||
renderComponent(); | ||
const messagePromptContainer = screen.queryByText("Scroll to new messages")?.parentElement; | ||
expect(messagePromptContainer).toHaveClass("rcb-message-prompt-container hidden"); | ||
}); | ||
|
||
it("applies hover styles when hovered", () => { | ||
renderComponent(); | ||
const messagePrompt = screen.getByText("Scroll to new messages"); | ||
|
||
// Before hover | ||
expect(messagePrompt).toHaveStyle({ color: "#fff", borderColor: "#ccc" }); | ||
|
||
// Hover | ||
fireEvent.mouseEnter(messagePrompt); | ||
expect(messagePrompt).toHaveStyle({ color: "#000", borderColor: "#000" }); | ||
|
||
// Leave hover | ||
fireEvent.mouseLeave(messagePrompt); | ||
expect(messagePrompt).toHaveStyle({ color: "#fff", borderColor: "#ccc" }); | ||
}); | ||
|
||
it("scrolls to the bottom when clicked", () => { | ||
renderComponent(); | ||
const messagePrompt = screen.getByText("Scroll to new messages"); | ||
|
||
fireEvent.mouseDown(messagePrompt); | ||
|
||
// Simulate scrolling completion | ||
jest.advanceTimersByTime(600); | ||
|
||
// Verify that setIsScrolling was called | ||
expect(mockSetIsScrolling).toHaveBeenCalledWith(false); | ||
}); | ||
}); |
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,138 @@ | ||
import { jest, SpyInstance } from "@jest/globals"; | ||
import * as VoiceService from "../../src/services/VoiceService"; | ||
|
||
describe("VoiceService", () => { | ||
let mockRecognition: jest.Mocked<SpeechRecognition>; | ||
let mockMediaRecorder: jest.Mocked<MediaRecorder>; | ||
let mockStopVoiceRecording: jest.SpyInstance<any, any>; | ||
|
||
beforeAll(() => { | ||
// Mock navigator.mediaDevices if undefined | ||
if (!navigator.mediaDevices) { | ||
Object.defineProperty(navigator, "mediaDevices", { | ||
value: { | ||
getUserMedia: jest.fn(), | ||
}, | ||
writable: true, | ||
}); | ||
} | ||
}); | ||
|
||
beforeEach(() => { | ||
// Mock SpeechRecognition | ||
mockRecognition = { | ||
start: jest.fn(), | ||
stop: jest.fn(), | ||
onresult: null, | ||
onend: null, | ||
} as unknown as jest.Mocked<SpeechRecognition>; | ||
|
||
window.SpeechRecognition = jest.fn(() => mockRecognition) as any; | ||
|
||
// Mock MediaRecorder | ||
mockMediaRecorder = { | ||
start: jest.fn(), | ||
stop: jest.fn(), | ||
ondataavailable: null, | ||
onstop: null, | ||
state: "inactive", | ||
} as unknown as jest.Mocked<MediaRecorder>; | ||
|
||
global.MediaRecorder = jest.fn(() => mockMediaRecorder) as any; | ||
|
||
// Mock getUserMedia | ||
jest.spyOn(navigator.mediaDevices, "getUserMedia").mockResolvedValue({ | ||
active: true, | ||
id: "mockStreamId", | ||
onaddtrack: null, | ||
onremovetrack: null, | ||
getTracks: jest.fn(() => [{ kind: "audio", stop: jest.fn() }]), | ||
addTrack: jest.fn(), | ||
removeTrack: jest.fn(), | ||
getAudioTracks: jest.fn(() => []), | ||
getVideoTracks: jest.fn(() => []), | ||
clone: jest.fn(), | ||
addEventListener: jest.fn(), | ||
removeEventListener: jest.fn(), | ||
dispatchEvent: jest.fn(), | ||
} as unknown as MediaStream); | ||
|
||
mockStopVoiceRecording = jest.spyOn(VoiceService, "stopVoiceRecording"); | ||
}); | ||
|
||
afterEach(() => { | ||
jest.restoreAllMocks(); // Clean up mocks after each test | ||
}); | ||
|
||
describe("startVoiceRecording", () => { | ||
it("should start SpeechRecognition when sendAsAudio is false", () => { | ||
const settings = { voice: { sendAsAudio: false, language: "en-US" } } as any; | ||
const mockToggleVoice = jest.fn(() => Promise.resolve()); | ||
|
||
VoiceService.startVoiceRecording( | ||
settings, | ||
mockToggleVoice, | ||
jest.fn(), | ||
jest.fn(), | ||
jest.fn(), | ||
{ current: [] }, | ||
{ current: null } | ||
); | ||
|
||
expect(mockRecognition.start).toHaveBeenCalled(); | ||
}); | ||
|
||
it("should start MediaRecorder when sendAsAudio is true", async () => { | ||
const settings = { voice: { sendAsAudio: true } } as any; | ||
const mockToggleVoice = jest.fn(() => Promise.resolve()); | ||
|
||
await VoiceService.startVoiceRecording( | ||
settings, | ||
mockToggleVoice, | ||
jest.fn(), | ||
jest.fn(), | ||
jest.fn(), | ||
{ current: [] }, | ||
{ current: null } | ||
); | ||
|
||
expect(navigator.mediaDevices.getUserMedia).toHaveBeenCalledWith({ audio: true }); | ||
expect(mockMediaRecorder.start).toHaveBeenCalled(); | ||
}); | ||
}); | ||
|
||
describe("stopVoiceRecording", () => { | ||
it("should stop SpeechRecognition and MediaRecorder", () => { | ||
VoiceService.stopVoiceRecording(); | ||
|
||
expect(mockRecognition.stop).toHaveBeenCalled(); | ||
expect(mockMediaRecorder.stop).toHaveBeenCalled(); | ||
}); | ||
}); | ||
|
||
describe("syncVoiceWithChatInput", () => { | ||
it("should start MediaRecorder if keepVoiceOn is true and sendAsAudio is enabled", () => { | ||
const settings = { voice: { sendAsAudio: true, disabled: false } } as any; | ||
|
||
VoiceService.syncVoiceWithChatInput(true, settings); | ||
|
||
expect(mockMediaRecorder.start).toHaveBeenCalled(); | ||
}); | ||
|
||
it("should start SpeechRecognition if keepVoiceOn is true and sendAsAudio is disabled", () => { | ||
const settings = { voice: { sendAsAudio: false, disabled: false } } as any; | ||
|
||
VoiceService.syncVoiceWithChatInput(true, settings); | ||
|
||
expect(mockRecognition.start).toHaveBeenCalled(); | ||
}); | ||
|
||
it("should stop all voice recording if keepVoiceOn is false", () => { | ||
const settings = { voice: { sendAsAudio: false, disabled: false } } as any; | ||
|
||
VoiceService.syncVoiceWithChatInput(false, settings); | ||
|
||
expect(mockStopVoiceRecording).toHaveBeenCalled(); | ||
}); | ||
}); | ||
}); |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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