diff --git a/__tests__/__mocks__/fileMock.ts b/__tests__/__mocks__/fileMock.ts index 92ede8ee..d12825e8 100644 --- a/__tests__/__mocks__/fileMock.ts +++ b/__tests__/__mocks__/fileMock.ts @@ -1,10 +1,12 @@ // __mocks__/fileMock.ts -export const botAvatar = "../../assets/bot_avatar.svg"; +export const audioIcon = "../../assets/audio_icon.svg"; +export const audioIconDisabled = "../../assets/audio_icon_disabled.svg"; export const actionDisabledIcon = "../../assets/action_disabled_icon.svg"; -export const emojiIcon = "../../assets/emoji_icon.svg"; +export const botAvatar = "../../assets/bot_avatar.svg"; export const closeChatIcon = "../../assets/close_chat_icon.svg"; +export const emojiIcon = "../../assets/emoji_icon.svg"; export const notificationIcon = "../../assets/notification_icon.svg"; export const notificationIconDisabled = "../../assets/notification_icon_disabled.svg"; -export const audioIcon = "../../assets/audio_icon.svg"; -export const audioIconDisabled = "../../assets/audio_icon_disabled.svg"; -export const sendIcon = "../../assets/send_icon.svg"; \ No newline at end of file +export const sendIcon = "../../assets/send_icon.svg"; +export const voiceIcon = "../../assets/voice_icon.svg"; +export const voiceIconDisabled = "../../assets/voice_icon_disabled.svg"; diff --git a/__tests__/components/buttons/VoiceButton.test.tsx b/__tests__/components/buttons/VoiceButton.test.tsx new file mode 100644 index 00000000..03aaf68e --- /dev/null +++ b/__tests__/components/buttons/VoiceButton.test.tsx @@ -0,0 +1,110 @@ +import React from "react"; + +import { expect } from "@jest/globals"; +import { render, screen, fireEvent } from "@testing-library/react"; +import "@testing-library/jest-dom/jest-globals"; + +import VoiceButton from "../../../src/components/Buttons/VoiceButton/VoiceButton"; +import { DefaultSettings } from "../../../src/constants/internal/DefaultSettings"; +import { useTextAreaInternal } from "../../../src/hooks/internal/useTextAreaInternal"; +import { TestChatBotProvider } from "../../__mocks__/TestChatBotContext"; +import { voiceIcon, voiceIconDisabled } from "../../__mocks__/fileMock"; + +jest.mock("../../../src/hooks/internal/useTextAreaInternal"); + +/** + * Helper function to render VoiceButton with different settings. + * + * @param disabled boolean indicating if voice option is disabled + * @param defaultToggledOn boolean indicating if voice option is toggled on by default + */ +const renderVoiceButton = (disabled: boolean, defaultToggledOn: boolean) => { + const initialSettings = { + voice: { + disabled: disabled, + defaultToggledOn: defaultToggledOn, + icon: voiceIcon, + iconDisabled: voiceIconDisabled, + }, + }; + return render( + + + + ); +}; + +/** + * Tests for VoiceButton component. + */ + +describe("VoiceButton Component", () => { + const voiceIconTestId = "rcb-voice-icon"; + + beforeEach(() => { + (useTextAreaInternal as jest.Mock).mockReturnValue({ + textAreaDisabled: false, + }); + }); + + it("renders with aria-label and initial state when defaultToggledOn is false and not disabled", () => { + renderVoiceButton(false, false); + + const button = screen.getByRole("button", { + name: DefaultSettings.ariaLabel?.voiceButton, + }); + const icon = screen.getByTestId(voiceIconTestId); + + expect(button).toBeInTheDocument(); + + expect(icon).toHaveStyle("fill: #9aa0a6"); + expect(icon.style.backgroundImage).toBe(`url(${voiceIconDisabled})`); + }); + + it("toggles voice state when clicked (initially off)", () => { + renderVoiceButton(false, false); + + const button = screen.getByRole("button", { + name: DefaultSettings.ariaLabel?.voiceButton, + }); + const icon = screen.getByTestId(voiceIconTestId); + + expect(icon.style.backgroundImage).toBe(`url(${voiceIconDisabled})`); + + fireEvent.mouseDown(button); + + expect(icon.style.backgroundImage).toBe(`url(${voiceIcon})`); + }); + + it("renders with voice toggled on initially and toggles to off when clicked", () => { + renderVoiceButton(false, true); + + const button = screen.getByRole("button", { + name: DefaultSettings.ariaLabel?.voiceButton, + }); + const icon = screen.getByTestId(voiceIconTestId); + expect(icon.style.backgroundImage).toBe(`url(${voiceIcon})`); + + fireEvent.mouseDown(button); + + expect(icon.style.backgroundImage).toBe(`url(${voiceIconDisabled})`); + }); + + it("toggles notification back to on after being toggled off", () => { + renderVoiceButton(false, true); + + const button = screen.getByRole("button", { + name: DefaultSettings.ariaLabel?.voiceButton, + }); + const icon = screen.getByTestId(voiceIconTestId); + expect(icon.style.backgroundImage).toBe(`url(${voiceIcon})`); + + fireEvent.mouseDown(button); + + expect(icon.style.backgroundImage).toBe(`url(${voiceIconDisabled})`); + + fireEvent.mouseDown(button); + + expect(icon.style.backgroundImage).toBe(`url(${voiceIcon})`); + }); +}); diff --git a/src/components/Buttons/VoiceButton/VoiceButton.tsx b/src/components/Buttons/VoiceButton/VoiceButton.tsx index c2144d16..e291b06c 100644 --- a/src/components/Buttons/VoiceButton/VoiceButton.tsx +++ b/src/components/Buttons/VoiceButton/VoiceButton.tsx @@ -110,6 +110,7 @@ const VoiceButton = () => { return ( )