diff --git a/__tests__/hooks/internal/useAudioInternal.test.ts b/__tests__/hooks/internal/useAudioInternal.test.ts index 32d36165..65c0600b 100644 --- a/__tests__/hooks/internal/useAudioInternal.test.ts +++ b/__tests__/hooks/internal/useAudioInternal.test.ts @@ -53,7 +53,7 @@ describe("useAudioInternal Hook", () => { expect(result.current.audioToggledOn).toBe(!initialAudioToggledOn); }); - it("should prevent toggling when event is defaultPrevented", () => { + it("should prevent toggling when event is defaultPrevented", async () => { // mocks rcb event handler const callRcbEventMock = jest.fn().mockReturnValue({ defaultPrevented: true }); mockUseRcbEventInternal.mockReturnValue({ @@ -69,8 +69,8 @@ describe("useAudioInternal Hook", () => { expect(result.current.audioToggledOn).toBe(initialAudioToggledOn); // simulates clicking the toggle action - act(() => { - result.current.toggleAudio(); + await act(async () => { + await result.current.toggleAudio(); }); // checks if callRcbEvent was called with rcb-toggle-audio and correct arguments diff --git a/__tests__/hooks/internal/useChatWindowInternal.test.ts b/__tests__/hooks/internal/useChatWindowInternal.test.ts index e841bf67..a947d6f4 100644 --- a/__tests__/hooks/internal/useChatWindowInternal.test.ts +++ b/__tests__/hooks/internal/useChatWindowInternal.test.ts @@ -53,7 +53,7 @@ describe("useChatWindowInternal Hook", () => { expect(result.current.isChatWindowOpen).toBe(!initialChatWindowOpen); }); - it("should prevent toggling when event is defaultPrevented", () => { + it("should prevent toggling when event is defaultPrevented", async () => { // mocks rcb event handler const callRcbEventMock = jest.fn().mockReturnValue({ defaultPrevented: true }); mockUseRcbEventInternal.mockReturnValue({ @@ -69,8 +69,8 @@ describe("useChatWindowInternal Hook", () => { expect(result.current.isChatWindowOpen).toBe(initialChatWindowOpen); // simulates clicking the toggle action - act(() => { - result.current.toggleChatWindow(); + await act(async () => { + await result.current.toggleChatWindow(); }); // checks if callRcbEvent was called with rcb-toggle-chat-window and correct arguments @@ -99,8 +99,8 @@ describe("useChatWindowInternal Hook", () => { expect(result.current.isChatWindowOpen).toBe(initialChatWindowOpen); // opens the chat window - act(() => { - result.current.openChat(true); + await act(async () => { + await result.current.openChat(true); }); // checks if callRcbEvent was called with rcb-toggle-chat-window and correct arguments diff --git a/__tests__/hooks/internal/useNotificationsInternal.test.ts b/__tests__/hooks/internal/useNotificationsInternal.test.ts index 0519ee15..5c4ac0cd 100644 --- a/__tests__/hooks/internal/useNotificationsInternal.test.ts +++ b/__tests__/hooks/internal/useNotificationsInternal.test.ts @@ -53,7 +53,7 @@ describe("useNotificationsInternal Hook", () => { expect(result.current.notificationsToggledOn).toBe(!initialNotificationsToggledOn); }); - it("should prevent toggling when event is defaultPrevented", () => { + it("should prevent toggling when event is defaultPrevented", async () => { // mocks rcb event handler const callRcbEventMock = jest.fn().mockReturnValue({ defaultPrevented: true }); mockUseRcbEventInternal.mockReturnValue({ @@ -69,8 +69,8 @@ describe("useNotificationsInternal Hook", () => { expect(result.current.notificationsToggledOn).toBe(initialNotificationsToggledOn); // simulates clicking the toggle action - act(() => { - result.current.toggleNotifications(); + await act(async () => { + await result.current.toggleNotifications(); }); // checks if callRcbEvent was called with rcb-toggle-notifications and correct arguments diff --git a/__tests__/hooks/internal/usePathsInternal.test.ts b/__tests__/hooks/internal/usePathsInternal.test.ts index 6c3d1fe9..8a978289 100644 --- a/__tests__/hooks/internal/usePathsInternal.test.ts +++ b/__tests__/hooks/internal/usePathsInternal.test.ts @@ -56,7 +56,7 @@ describe("usePathsInternal Hook", () => { const { result } = renderHook(() => usePathsInternal()); await act(async () => { - const success = result.current.goToPath("newPath"); + const success = await result.current.goToPath("newPath"); expect(success).toBe(true); }); @@ -88,7 +88,7 @@ describe("usePathsInternal Hook", () => { const { result } = renderHook(() => usePathsInternal()); await act(async () => { - const success = result.current.goToPath("blockedPath"); + const success = await result.current.goToPath("blockedPath"); expect(success).toBe(false); }); diff --git a/__tests__/hooks/internal/useTextAreaInternal.test.ts b/__tests__/hooks/internal/useTextAreaInternal.test.ts index 99512d39..26a135a0 100644 --- a/__tests__/hooks/internal/useTextAreaInternal.test.ts +++ b/__tests__/hooks/internal/useTextAreaInternal.test.ts @@ -124,7 +124,7 @@ describe("useTextAreaInternal Hook", () => { expect(result.current.getTextAreaValue().length).toBe(1000); }); - it("should prevent setting value if event is defaultPrevented", () => { + it("should prevent setting value if event is defaultPrevented", async () => { const callRcbEventMock = jest.fn().mockReturnValue({ defaultPrevented: true }); mockUseRcbEventInternal.mockReturnValue({ callRcbEvent: callRcbEventMock, @@ -136,8 +136,8 @@ describe("useTextAreaInternal Hook", () => { const { result } = renderHook(() => useTextAreaInternal()); - act(() => { - result.current.setTextAreaValue("Test value"); + await act(async () => { + await result.current.setTextAreaValue("Test value"); }); expect(result.current.getTextAreaValue()).toBe(""); diff --git a/__tests__/hooks/internal/useToastsInternal.test.tsx b/__tests__/hooks/internal/useToastsInternal.test.tsx index 1a0f547a..9b063d1f 100644 --- a/__tests__/hooks/internal/useToastsInternal.test.tsx +++ b/__tests__/hooks/internal/useToastsInternal.test.tsx @@ -63,14 +63,14 @@ describe('useToastsInternal', () => { jest.clearAllMocks(); }); - it('should add a new toast when not exceeding maxCount', () => { + it('should add a new toast when not exceeding maxCount', async () => { // Test adding a toast when maxCount is not reached mockRcbEventInternal.callRcbEvent.mockReturnValue({ defaultPrevented: false, data: { toast: { id: 'mocked-uuid', content: 'New toast content', timeout: undefined } } }); const { result } = renderHook(() => useToastsInternal()); - act(() => { - result.current.showToast('New toast content'); + await act(async () => { + await result.current.showToast('New toast content'); }); expect(generateSecureUUID).toHaveBeenCalled(); expect(mockToastsContext.setToasts).toHaveBeenCalledWith(expect.any(Function)); @@ -81,16 +81,16 @@ describe('useToastsInternal', () => { expect(newToasts).toEqual([{ id: 'mocked-uuid', content: 'New toast content', timeout: undefined }]); }); - it('should not add a new toast if maxCount is reached and forbidOnMax is true', () => { + it('should not add a new toast if maxCount is reached and forbidOnMax is true', async () => { // Test forbidding new toast if maxCount is reached mockToastsContext.toasts = [{ id: '1' }, { id: '2' }, { id: '3' }]; const { result } = renderHook(() => useToastsInternal()); - const toastId = result.current.showToast('Toast content'); + const toastId = await result.current.showToast('Toast content'); expect(toastId).toBeNull(); expect(mockToastsContext.setToasts).not.toHaveBeenCalled(); }); - it('should remove the oldest toast and add a new one if maxCount is reached but forbidOnMax is false', () => { + it('should remove the oldest toast and add a new one if maxCount is reached but forbidOnMax is false', async () => { // Test replacing oldest toast if maxCount reached and forbidOnMax is false mockSettingsContext.settings.toast.forbidOnMax = false; mockToastsContext.toasts = [{ id: '1' }, { id: '2' }, { id: '3' }]; @@ -99,8 +99,8 @@ describe('useToastsInternal', () => { content: 'New toast content', timeout: undefined } } }); const { result } = renderHook(() => useToastsInternal()); - act(() => { - result.current.showToast('New toast content'); + await act(async () => { + await result.current.showToast('New toast content'); }); expect(mockToastsContext.setToasts).toHaveBeenCalledWith(expect.any(Function)); @@ -114,14 +114,14 @@ describe('useToastsInternal', () => { ]); }); - it('should dismiss a toast by id', () => { + it('should dismiss a toast by id', async () => { // Test dismissing a toast by ID const toast = { id: 'toast-1', content: 'Toast to dismiss' }; mockToastsContext.toasts = [toast]; mockRcbEventInternal.callRcbEvent.mockReturnValue({ defaultPrevented: false }); const { result } = renderHook(() => useToastsInternal()); - act(() => { - result.current.dismissToast('toast-1'); + await act(async () => { + await result.current.dismissToast('toast-1'); }); expect(mockToastsContext.setToasts).toHaveBeenCalledWith(expect.any(Function)); @@ -131,32 +131,32 @@ describe('useToastsInternal', () => { expect(updatedToasts).toEqual([]); }); - it('should not dismiss a toast if the id is not found', () => { + it('should not dismiss a toast if the id is not found', async () => { // Test no dismissal if ID not found mockToastsContext.toasts = [{ id: 'toast-2', content: 'Another toast' }]; const { result } = renderHook(() => useToastsInternal()); - const resultId = result.current.dismissToast('invalid-id'); + const resultId = await result.current.dismissToast('invalid-id'); expect(resultId).toBeNull(); expect(mockToastsContext.setToasts).not.toHaveBeenCalled(); }); - it('should not show toast if rcbShowToast event is prevented', () => { + it('should not show toast if rcbShowToast event is prevented', async () => { // Test prevention of toast display by event mockRcbEventInternal.callRcbEvent.mockReturnValue({ defaultPrevented: true }); const { result } = renderHook(() => useToastsInternal()); - const resultId = result.current.showToast('Prevented toast'); + const resultId = await result.current.showToast('Prevented toast'); expect(resultId).toBeNull(); expect(mockToastsContext.setToasts).not.toHaveBeenCalled(); }); - it('should call rcbDismissToast event when dismissing a toast', () => { + it('should call rcbDismissToast event when dismissing a toast', async () => { // Test triggering of dismiss event upon toast removal const toast = { id: 'toast-1', content: 'Toast to dismiss' }; mockToastsContext.toasts = [toast]; mockRcbEventInternal.callRcbEvent.mockReturnValue({ defaultPrevented: false }); const { result } = renderHook(() => useToastsInternal()); - act(() => { - result.current.dismissToast('toast-1'); + await act(async () => { + await result.current.dismissToast('toast-1'); }); expect(mockRcbEventInternal.callRcbEvent).toHaveBeenCalledWith(RcbEvent.DISMISS_TOAST, { toast }); }); diff --git a/__tests__/services/RcbEventService.test.ts b/__tests__/services/RcbEventService.test.ts index 135608d0..966afb01 100644 --- a/__tests__/services/RcbEventService.test.ts +++ b/__tests__/services/RcbEventService.test.ts @@ -24,7 +24,7 @@ describe('emitRcbEvent', () => { }); // Test for emitting a cancellable event - it('should emit a cancellable event and return the event', () => { + it('should emit a cancellable event and return the event', async () => { const eventName = RcbEvent.TOGGLE_AUDIO; const eventDetail: EventDetail = { botId: 'testBotId', @@ -34,7 +34,7 @@ describe('emitRcbEvent', () => { const data = { someData: 'testData' }; // Call emitRcbEvent and capture the result - const result = emitRcbEvent(eventName, eventDetail, data); + const result = await emitRcbEvent(eventName, eventDetail, data); // Verify that the event was dispatched correctly if (dispatchedEvent) { @@ -49,7 +49,7 @@ describe('emitRcbEvent', () => { }); // Test for emitting a non-cancellable event - it('should emit a non-cancellable event and return the event', () => { + it('should emit a non-cancellable event and return the event', async () => { const eventName = RcbEvent.POST_INJECT_MESSAGE; const eventDetail: EventDetail = { botId: 'testBotId', @@ -58,7 +58,7 @@ describe('emitRcbEvent', () => { }; const data = { someData: 'testData' }; - const result = emitRcbEvent(eventName, eventDetail, data); + const result = await emitRcbEvent(eventName, eventDetail, data); // Verify that the event was dispatched as non-cancellable if (dispatchedEvent) { @@ -73,7 +73,7 @@ describe('emitRcbEvent', () => { }); // Test for handling an event with empty data - it('should handle an event with empty data', () => { + it('should handle an event with empty data', async () => { const eventName = RcbEvent.TOGGLE_VOICE; const eventDetail: EventDetail = { botId: 'testBotId', @@ -81,7 +81,7 @@ describe('emitRcbEvent', () => { prevPath: 'testPreviousPath' }; - const result = emitRcbEvent(eventName, eventDetail, {}); + const result = await emitRcbEvent(eventName, eventDetail, {}); // Verify the event was dispatched with empty data if (dispatchedEvent) { @@ -95,10 +95,10 @@ describe('emitRcbEvent', () => { }); // Test for handling an event with no detail and empty data - it('should handle an event with no detail and data', () => { + it('should handle an event with no detail and data', async () => { const eventName = RcbEvent.CHANGE_PATH; - const result = emitRcbEvent(eventName, { + const result = await emitRcbEvent(eventName, { botId: null, currPath: null, prevPath: null diff --git a/src/components/Buttons/AudioButton/AudioButton.tsx b/src/components/Buttons/AudioButton/AudioButton.tsx index 900190f0..b2576bc1 100644 --- a/src/components/Buttons/AudioButton/AudioButton.tsx +++ b/src/components/Buttons/AudioButton/AudioButton.tsx @@ -63,9 +63,9 @@ const AudioButton = () => {
{ + onMouseDown={async (event: MouseEvent) => { event.preventDefault(); - toggleAudio(); + await toggleAudio(); }} style={audioToggledOn ? styles.audioButtonStyle diff --git a/src/components/Buttons/NotificationButton/NotificationButton.tsx b/src/components/Buttons/NotificationButton/NotificationButton.tsx index 1d2b0c30..298120f9 100644 --- a/src/components/Buttons/NotificationButton/NotificationButton.tsx +++ b/src/components/Buttons/NotificationButton/NotificationButton.tsx @@ -65,9 +65,9 @@ const NotificationButton = () => {
{ + onMouseDown={async (event: MouseEvent) => { event.preventDefault(); - toggleNotifications(); + await toggleNotifications(); }} style={notificationsToggledOn ? styles.notificationButtonStyle diff --git a/src/components/Buttons/VoiceButton/VoiceButton.tsx b/src/components/Buttons/VoiceButton/VoiceButton.tsx index 376ebd21..c4716e6b 100644 --- a/src/components/Buttons/VoiceButton/VoiceButton.tsx +++ b/src/components/Buttons/VoiceButton/VoiceButton.tsx @@ -126,12 +126,12 @@ const VoiceButton = () => {
{ + onMouseDown={async (event: MouseEvent) => { event.preventDefault(); if (textAreaDisabled) { return; } - toggleVoice(); + await toggleVoice(); }} style={voiceToggledOn && !textAreaDisabled ? styles.voiceButtonStyle diff --git a/src/components/ChatBotBody/ToastPrompt/ToastPrompt.tsx b/src/components/ChatBotBody/ToastPrompt/ToastPrompt.tsx index 1e1e24af..0df94538 100644 --- a/src/components/ChatBotBody/ToastPrompt/ToastPrompt.tsx +++ b/src/components/ChatBotBody/ToastPrompt/ToastPrompt.tsx @@ -78,10 +78,10 @@ const Toast = ({ onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave} style={isHovered ? toastPromptHoveredStyle : localizedStyles.toastPromptStyle} - onMouseDown={(event: MouseEvent) => { + onMouseDown={async (event: MouseEvent) => { if (settings.toast?.dismissOnClick) { event.preventDefault(); - dismissToast(id); + await dismissToast(id); } }} className="rcb-toast-prompt" diff --git a/src/hooks/internal/useAudioInternal.ts b/src/hooks/internal/useAudioInternal.ts index e81f012d..f3371c68 100644 --- a/src/hooks/internal/useAudioInternal.ts +++ b/src/hooks/internal/useAudioInternal.ts @@ -23,7 +23,9 @@ export const useAudioInternal = () => { const toggleAudio = useCallback(async () => { // handles toggle audio event if (settings.event?.rcbToggleAudio) { - const event = await callRcbEvent(RcbEvent.TOGGLE_AUDIO, {currState: audioToggledOn, newState: !audioToggledOn}); + const event = await callRcbEvent( + RcbEvent.TOGGLE_AUDIO, {currState: audioToggledOn, newState: !audioToggledOn} + ); if (event.defaultPrevented) { return; } diff --git a/src/hooks/internal/useChatWindowInternal.ts b/src/hooks/internal/useChatWindowInternal.ts index b3ced257..f98e2e80 100644 --- a/src/hooks/internal/useChatWindowInternal.ts +++ b/src/hooks/internal/useChatWindowInternal.ts @@ -57,11 +57,11 @@ export const useChatWindowInternal = () => { * * @param isOpen boolean indicating whether to open/close the chat window */ - const openChat = useCallback((isOpen: boolean) => { + const openChat = useCallback(async (isOpen: boolean) => { if (isChatWindowOpen === isOpen) { return; } - toggleChatWindow(); + await toggleChatWindow(); }, [isChatWindowOpen]); return { diff --git a/src/services/BlockService/TransitionProcessor.ts b/src/services/BlockService/TransitionProcessor.ts index 3656a18b..78c32a20 100644 --- a/src/services/BlockService/TransitionProcessor.ts +++ b/src/services/BlockService/TransitionProcessor.ts @@ -13,7 +13,8 @@ import { Params } from "../../types/Params"; * @param setTimeoutId sets the timeout id for the transition attribute if it is interruptable */ export const processTransition = async (flow: Flow, path: keyof Flow, params: Params, - goToPath: (pathToGo: string) => Promise, setTimeoutId: (timeoutId: ReturnType) => void) => { + goToPath: (pathToGo: string) => Promise, + setTimeoutId: (timeoutId: ReturnType) => void) => { const block = flow[path]; diff --git a/src/services/VoiceService.ts b/src/services/VoiceService.ts index 53f9008b..a0fe297c 100644 --- a/src/services/VoiceService.ts +++ b/src/services/VoiceService.ts @@ -34,7 +34,7 @@ const getSpeechRecognition = () => { */ export const startVoiceRecording = ( settings: Settings, - toggleVoice: () => void, + toggleVoice: () => Promise, triggerSendVoiceInput: () => void, setTextAreaValue: (value: string) => void, setInputLength: Dispatch>, @@ -63,7 +63,7 @@ export const startVoiceRecording = ( */ const startSpeechRecognition = ( settings: Settings, - toggleVoice: () => void, + toggleVoice: () => Promise, triggerSendVoiceInput: () => void, setTextAreaValue: (value: string) => void, setInputLength: Dispatch>, @@ -106,7 +106,7 @@ const startSpeechRecognition = ( setInputLength(inputRef.current.value.length); } - inactivityTimer = setTimeout(() => handleTimeout(toggleVoice, inputRef), inactivityPeriod); + inactivityTimer = setTimeout(async () => await handleTimeout(toggleVoice, inputRef), inactivityPeriod); if (!settings.voice?.autoSendDisabled) { autoSendTimer = setTimeout(triggerSendVoiceInput, autoSendPeriod); } @@ -116,7 +116,7 @@ const startSpeechRecognition = ( if (toggleOn) { recognition.start(); if (!inactivityTimer) { - inactivityTimer = setTimeout(() => handleTimeout(toggleVoice, inputRef), inactivityPeriod); + inactivityTimer = setTimeout(async () => await handleTimeout(toggleVoice, inputRef), inactivityPeriod); } } else { clearTimeout(inactivityTimer as ReturnType); @@ -125,7 +125,7 @@ const startSpeechRecognition = ( } }; - inactivityTimer = setTimeout(() => handleTimeout(toggleVoice, inputRef), inactivityPeriod); + inactivityTimer = setTimeout(async () => await handleTimeout(toggleVoice, inputRef), inactivityPeriod); } /** @@ -222,9 +222,11 @@ export const syncVoiceWithChatInput = (keepVoiceOn: boolean, settings: Settings) * * @param handleToggleVoice handles toggling of voice */ -const handleTimeout = (toggleVoice: () => void, inputRef: RefObject) => { +const handleTimeout = async (toggleVoice: () => Promise, + inputRef: RefObject) => { + if (!inputRef.current?.disabled) { - toggleVoice(); + await toggleVoice(); } stopVoiceRecording(); } \ No newline at end of file diff --git a/src/types/Params.ts b/src/types/Params.ts index f4ccc244..dcfbb904 100644 --- a/src/types/Params.ts +++ b/src/types/Params.ts @@ -7,6 +7,7 @@ export type Params = { userInput: string; currPath: keyof Flow | null; prevPath: keyof Flow | null; + files?: FileList; goToPath: (pathToGo: keyof Flow) => Promise; setTextAreaValue: (value: string) => Promise; injectMessage: (content: string | JSX.Element, sender?: string) => Promise; @@ -15,6 +16,5 @@ export type Params = { endStreamMessage: (sender: string) => Promise; showToast: (content: string | JSX.Element, timeout?: number) => Promise; dismissToast: (id: string) => Promise; - openChat: (isOpen: boolean) => void; - files?: FileList; + openChat: (isOpen: boolean) => Promise; } \ No newline at end of file