Repository: tjtanjin/react-chatbotify
Pull request #181 (2024-10-10 08:55:47)

Wrote test cases for FunctionProcessor
#### Description

Added unit tests for the `processFunction` in `BlockService/FunctionProcessor` to ensure correct functionality when handling blocks with and without functions, handling promises, and managing errors.

Closes # (issue)

#### What change does this PR introduce?

Please select the relevant option(s).

- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Documentation update (changes to docs/code comments)

#### What is the proposed approach?

Implemented unit tests using Jest to verify the behavior of the `processFunction`. The tests cover:
- Returning `undefined` when the block has no function.
- Returning the result of the function when it is not a promise.
- Returning the resolved value of the function when it is a promise.
- Handling function throwing an error.
- Handling function returning a rejected promise.

Screenshot - 
![image](https://github.com/user-attachments/assets/6c19fb65-d267-4b76-8a4b-d4f5ec5b9655)


#### Checklist:

- [x] My code follows the code style of this project.
- [ ] My change requires a change to the documentation.
- [] I have updated the documentation accordingly.
- [x] I have added tests to cover my changes.
- [x] All new and existing tests passed.


- [ ] The commit message follows our adopted [guidelines](https://www.conventionalcommits.org/en/v1.0.0/)
- [ ] Testing has been done for the change(s) added (for bug fixes/features)
- [ ] Relevant comments/docs have been added/updated (for bug fixes/features)

Pratik00019: @tjtanjin  Hey can you pls review my PR and add tag of hacktoberfest-accepted.
Thank you
Pratik00019: Hello @tjtanjin,

I have updated my PR with the requested changes. Can you please review it and, if everything is in order, merge it and label it as `hacktoberfest-accepted`?

Thank you!
Pratik00019: Hello @tjtanjin,

I have updated my pull request (PR) as per your suggestions. The unit tests now use jest.fn() for mocking functions, and the mocks are set up in the beforeEach block to ensure clean state for each test.

Could you please review the updated PR and merge it if everything looks good? Also, it would be great if you could add the hacktoberfest-accepted label as this is my first open source contribution.

Thank you for your guidance and support!

Patch:
diff --git a/src/components/Buttons/VoiceButton/VoiceButton.css b/src/components/Buttons/VoiceButton/VoiceButton.css
index 0df02ac..3208bac 100644
--- a/src/components/Buttons/VoiceButton/VoiceButton.css
+++ b/src/components/Buttons/VoiceButton/VoiceButton.css
@@ -49,20 +49,9 @@
 }
 
 .rcb-voice-icon-on {
-    animation: ping 1s infinite;
+    animation: rcb-animation-ping 1s infinite;
 }
 
 .rcb-voice-icon-off {
     filter: grayscale(100%);
-}
-
-@keyframes ping {
-    0% {
-        filter: brightness(100%);
-        opacity: 1;
-    }
-    50% {
-        filter: brightness(50%);
-        opacity: 0.8;
-    }
 }
\ No newline at end of file
diff --git a/src/components/ChatBotBody/ChatBotBody.css b/src/components/ChatBotBody/ChatBotBody.css
index 93afed8..40f8fcf 100644
--- a/src/components/ChatBotBody/ChatBotBody.css
+++ b/src/components/ChatBotBody/ChatBotBody.css
@@ -66,18 +66,7 @@
 }
 
 .rcb-bot-message-entry {
-	animation: bot-entry 0.3s ease-in backwards;
-}
-
-@keyframes bot-entry {
-	0% {
-		transform: translate(-100%, 50%) scale(0);
-		opacity: 0;
-	}
-	100% {
-		transform: translate(0, 0) scale(1);
-		opacity: 1;
-	}
+	animation: rcb-animation-bot-message-entry 0.3s ease-in backwards;
 }
 
 .rcb-user-message {
@@ -90,18 +79,7 @@
 }
 
 .rcb-user-message-entry {
-	animation: user-entry 0.3s ease-in backwards;
-}
-
-@keyframes user-entry {
-	0% {
-		transform: translate(100%, 50%) scale(0);
-		opacity: 0;
-	}
-	100% {
-		transform: translate(0, 0) scale(1);
-		opacity: 1;
-	}
+	animation: rcb-animation-user-message-entry 0.3s ease-in backwards;
 }
 
 .rcb-message-bot-avatar,
@@ -136,7 +114,7 @@
 	border-radius: 50%;
 	background-color: #ccc;
 	margin-right: 4px;
-	animation: rcb-typing 1s infinite;
+	animation: rcb-animation-bot-typing 1s infinite;
 }
 
 .rcb-dot:nth-child(2) {
@@ -147,18 +125,6 @@
   	animation-delay: 0.4s;
 }
 
-@keyframes rcb-typing {
-	0% {
-		opacity: 0.4;
-	}
-	50% {
-		opacity: 1
-	}
-	100% {
-		opacity: 0.4;
-	}
-}
-
 /* Toast Container */
 .rcb-toast-prompt-container {
     position: absolute;
diff --git a/src/components/ChatBotBody/ChatMessagePrompt/ChatMessagePrompt.css b/src/components/ChatBotBody/ChatMessagePrompt/ChatMessagePrompt.css
index 8e7bcd0..cacaef2 100644
--- a/src/components/ChatBotBody/ChatMessagePrompt/ChatMessagePrompt.css
+++ b/src/components/ChatBotBody/ChatMessagePrompt/ChatMessagePrompt.css
@@ -1,48 +1,34 @@
 .rcb-message-prompt-container.visible {
-    position: sticky;
-    bottom: 0px;
-    margin: auto;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    opacity: 1;
-    animation: popIn 0.3s ease-in-out;
-    pointer-events: auto;
+	position: sticky;
+	bottom: 0px;
+	margin: auto;
+	display: flex;
+	align-items: center;
+	justify-content: center;
+	opacity: 1;
+	animation: rcb-animation-pop-in 0.3s ease-in-out;
+	pointer-events: auto;
 }
 
 .rcb-message-prompt-container.hidden {
-    opacity: 0;
-    height: 0px; /* work around for hiding element while still having animation */
-    visibility: hidden;
-    pointer-events: none;
+	opacity: 0;
+	height: 0px; /* work around for hiding element while still having animation */
+	visibility: hidden;
+	pointer-events: none;
 }
 
 .rcb-message-prompt-text {
-    padding: 6px 12px;
-    border-radius: 20px;
-    color: #adadad;
-    font-size: 12px;
-    background-color: #fff;
-    border: 0.5px solid #adadad;
-    cursor: pointer;
-    transition: color 0.3s ease, border-color 0.3s ease;
-    z-index: 9999;
+	padding: 6px 12px;
+	border-radius: 20px;
+	color: #adadad;
+	font-size: 12px;
+	background-color: #fff;
+	border: 0.5px solid #adadad;
+	cursor: pointer;
+	transition: color 0.3s ease, border-color 0.3s ease;
+	z-index: 9999;
 }
 
 .rcb-message-prompt-container.hidden .rcb-message-prompt-text {
-    padding: 0px;
-}
-
-@keyframes popIn {
-    0% {
-      transform: scale(0.8);
-      opacity: 0;
-    }
-    70% {
-      transform: scale(1.1);
-      opacity: 1;
-    }
-    100% {
-      transform: scale(1);
-    }
-}
+	padding: 0px;
+}
\ No newline at end of file
diff --git a/src/components/ChatBotBody/MediaDisplay/MediaDisplay.css b/src/components/ChatBotBody/MediaDisplay/MediaDisplay.css
index a1629ac..31045cb 100644
--- a/src/components/ChatBotBody/MediaDisplay/MediaDisplay.css
+++ b/src/components/ChatBotBody/MediaDisplay/MediaDisplay.css
@@ -43,16 +43,5 @@
 /* Media Display Entry Animations */
 
 .rcb-media-entry {
-	animation: media-entry 0.3s ease-in backwards;
-}
-
-@keyframes media-entry {
-	0% {
-		transform: translate(100%, 50%) scale(0);
-		opacity: 0;
-	}
-	100% {
-		transform: translate(0, 0) scale(1);
-		opacity: 1;
-	}
+	animation: rcb-animation-user-message-entry 0.3s ease-in backwards;
 }
diff --git a/src/components/ChatBotBody/ToastPrompt/ToastPrompt.css b/src/components/ChatBotBody/ToastPrompt/ToastPrompt.css
index 219e650..c351f77 100644
--- a/src/components/ChatBotBody/ToastPrompt/ToastPrompt.css
+++ b/src/components/ChatBotBody/ToastPrompt/ToastPrompt.css
@@ -1,28 +1,15 @@
-.rcb-toast-prompt-text {
-    padding: 6px 12px;
-    border-radius: 5px;
-    color: #7a7a7a;
-    font-size: 12px;
-    text-align: center;
-    background-color: #fff;
-    border: 0.5px solid #7a7a7a;
-    cursor: pointer;
-    transition: color 0.3s ease, border-color 0.3s ease;
-    z-index: 9999;
-    width: 100%;
-    margin-top: 6px;
-}
-
-@keyframes popIn {
-    0% {
-      transform: scale(0.8);
-      opacity: 0;
-    }
-    70% {
-      transform: scale(1.1);
-      opacity: 1;
-    }
-    100% {
-      transform: scale(1);
-    }
-}
+.rcb-toast-prompt {
+	padding: 6px 12px;
+	border-radius: 5px;
+	color: #7a7a7a;
+	font-size: 12px;
+	text-align: center;
+	background-color: #fff;
+	border: 0.5px solid #7a7a7a;
+	cursor: pointer;
+	transition: color 0.3s ease, border-color 0.3s ease;
+	z-index: 9999;
+	width: 100%;
+	margin-top: 6px;
+	animation: rcb-animation-pop-in 0.3s ease-in-out;
+}
\ No newline at end of file
diff --git a/src/components/ChatBotBody/ToastPrompt/ToastPrompt.tsx b/src/components/ChatBotBody/ToastPrompt/ToastPrompt.tsx
index c8ca5dd..21d1b12 100644
--- a/src/components/ChatBotBody/ToastPrompt/ToastPrompt.tsx
+++ b/src/components/ChatBotBody/ToastPrompt/ToastPrompt.tsx
@@ -78,7 +78,7 @@ const Toast = ({
 						dismissToast(id);
 					}
 				}}
-				className="rcb-toast-prompt-text"
+				className="rcb-toast-prompt"
 			>
 				{content}
 			</div>
diff --git a/src/components/ChatBotBody/UserCheckboxes/UserCheckboxes.css b/src/components/ChatBotBody/UserCheckboxes/UserCheckboxes.css
index af6b42c..8e6554e 100644
--- a/src/components/ChatBotBody/UserCheckboxes/UserCheckboxes.css
+++ b/src/components/ChatBotBody/UserCheckboxes/UserCheckboxes.css
@@ -26,7 +26,7 @@
 	width: 80%;
 	cursor: pointer;
 	background-color: #fff;
-	animation: checkboxes-entry 0.5s ease-out;
+	animation: rcb-animations-checkboxes-entry 0.5s ease-out;
 	overflow: hidden;
 }
 
@@ -34,17 +34,6 @@
 	box-shadow: 0 0 5px rgba(0, 0, 0, 0.2); 
 }
 
-@keyframes checkboxes-entry {
-	0% {
-	  transform: translateX(-100%);
-	  opacity: 0;
-	}
-	100% {
-	  transform: translateX(0);
-	  opacity: 1;
-	}
-}
-
 /* Checkbox Row */
 
 .rcb-checkbox-row {
@@ -100,7 +89,7 @@
 	width: 80%;
 	cursor: pointer;
 	background-color: #fff;
-	animation: checkboxes-entry 0.5s ease-out;
+	animation: rcb-animations-checkboxes-entry 0.5s ease-out;
 }
 
 .rcb-checkbox-next-button::before {
diff --git a/src/components/ChatBotBody/UserOptions/UserOptions.css b/src/components/ChatBotBody/UserOptions/UserOptions.css
index 64060af..4984dd5 100644
--- a/src/components/ChatBotBody/UserOptions/UserOptions.css
+++ b/src/components/ChatBotBody/UserOptions/UserOptions.css
@@ -26,21 +26,10 @@
 	border-style: solid;
 	cursor: pointer;
 	transition: background-color 0.3s ease;
-	animation: options-entry 0.5s ease-out;
+	animation: rcb-animation-options-entry 0.5s ease-out;
 	overflow: hidden;
 }
 
-@keyframes options-entry {
-	0% {
-	  transform: scale(0);
-	  opacity: 0;
-	}
-	100% {
-	  transform: scale(1);
-	  opacity: 1;
-	}
-}
-
 .rcb-options:hover {
 	box-shadow: 0 0 5px rgba(0, 0, 0, 0.2); 
 }
\ No newline at end of file
diff --git a/src/components/ChatBotButton/ChatBotButton.css b/src/components/ChatBotButton/ChatBotButton.css
index e73ca28..6a29421 100644
--- a/src/components/ChatBotButton/ChatBotButton.css
+++ b/src/components/ChatBotButton/ChatBotButton.css
@@ -18,13 +18,13 @@
 .rcb-toggle-button.rcb-button-hide {
 	opacity: 0;
 	visibility: hidden;
-	animation: collapse 0.3s ease-in-out forwards;
+	animation: rcb-animation-collapse 0.3s ease-in-out forwards;
 }
 
 .rcb-toggle-button.rcb-button-show {
 	opacity: 1;
 	visibility: visible;
-	animation: expand 0.3s ease-in-out forwards;
+	animation: rcb-animation-expand 0.3s ease-in-out forwards;
 }
 
 /* ChatBot Toggle Icon */
@@ -42,28 +42,6 @@
 	border-radius: inherit;
 }
 
-@keyframes expand {
-	0% {
-		transform: translate(100%, 100%) scale(0);
-		opacity: 0;
-	}
-	100% {
-		transform: translate(0, 0) scale(1);
-		opacity: 1;
-	}
-}
-
-@keyframes collapse {
-	0% {
-		transform: translate(0, 0) scale(1);
-		opacity: 1;
-	}
-	100% {
-		transform: translate(100%, 100%) scale(0);
-		opacity: 0;
-	}
-}
-
 /* ChatBot Notification Badge*/
 
 .rcb-badge {
diff --git a/src/components/ChatBotContainer.css b/src/components/ChatBotContainer.css
index ad4e66f..05df8b9 100644
--- a/src/components/ChatBotContainer.css
+++ b/src/components/ChatBotContainer.css
@@ -38,16 +38,18 @@
 .rcb-window-open .rcb-chat-window {
 	opacity: 1;
 	visibility: visible;
-	animation: expand 0.3s ease-in-out forwards;
+	animation: rcb-animation-expand 0.3s ease-in-out forwards;
 }
 
 .rcb-window-close .rcb-chat-window {
 	opacity: 0;
 	visibility: hidden;
-	animation: collapse 0.3s ease-in-out forwards;
+	animation: rcb-animation-collapse 0.3s ease-in-out forwards;
 }
 
-@keyframes expand {
+/* Animations used throughout the entire chatbot */
+
+@keyframes rcb-animation-expand {
 	0% {
 		transform: translate(100%, 100%) scale(0);
 		opacity: 0;
@@ -58,7 +60,7 @@
 	}
 }
 
-@keyframes collapse {
+@keyframes rcb-animation-collapse {
 	0% {
 		transform: translate(0, 0) scale(1);
 		opacity: 1;
@@ -68,3 +70,115 @@
 		opacity: 0;
 	}
 }
+
+@keyframes rcb-animation-ping {
+    0% {
+        filter: brightness(100%);
+        opacity: 1;
+    }
+    50% {
+        filter: brightness(50%);
+        opacity: 0.8;
+    }
+}
+
+@keyframes rcb-animation-bot-message-entry {
+	0% {
+		transform: translate(-100%, 50%) scale(0);
+		opacity: 0;
+	}
+	100% {
+		transform: translate(0, 0) scale(1);
+		opacity: 1;
+	}
+}
+
+@keyframes rcb-animation-user-message-entry {
+	0% {
+		transform: translate(100%, 50%) scale(0);
+		opacity: 0;
+	}
+	100% {
+		transform: translate(0, 0) scale(1);
+		opacity: 1;
+	}
+}
+
+@keyframes rcb-animation-bot-typing {
+	0% {
+		opacity: 0.4;
+	}
+	50% {
+		opacity: 1
+	}
+	100% {
+		opacity: 0.4;
+	}
+}
+
+@keyframes rcb-animation-pop-in {
+	0% {
+		transform: scale(0.8);
+		opacity: 0;
+	}
+	70% {
+		transform: scale(1.1);
+		opacity: 1;
+	}
+	100% {
+		transform: scale(1);
+	}
+}
+
+@keyframes rcb-animations-checkboxes-entry {
+	0% {
+	  transform: translateX(-100%);
+	  opacity: 0;
+	}
+	100% {
+	  transform: translateX(0);
+	  opacity: 1;
+	}
+}
+
+@keyframes rcb-animation-options-entry {
+	0% {
+	  transform: scale(0);
+	  opacity: 0;
+	}
+	100% {
+	  transform: scale(1);
+	  opacity: 1;
+	}
+}
+
+@keyframes rcb-animation-tooltip-in {
+	0% {
+	  opacity: 0;
+	  transform: translateY(-5px);
+	}
+	100% {
+	  opacity: 1;
+	  transform: translateY(0);
+	}
+  }
+  
+@keyframes rcb-animation-tooltip-out {
+	0% {
+	  opacity: 1;
+	  transform: translateY(0);
+	}
+	100% {
+	  opacity: 0;
+	  transform: translateY(-5px);
+	}
+}
+
+@keyframes rcb-animation-spin {
+	0% {
+		transform: rotate(0deg);
+	}
+	100% {
+		transform: rotate(360deg);
+	}
+}
\ No newline at end of file
diff --git a/src/components/ChatBotTooltip/ChatBotTooltip.css b/src/components/ChatBotTooltip/ChatBotTooltip.css
index 3cecd7a..f2d4733 100644
--- a/src/components/ChatBotTooltip/ChatBotTooltip.css
+++ b/src/components/ChatBotTooltip/ChatBotTooltip.css
@@ -24,33 +24,11 @@
 .rcb-chat-tooltip.rcb-tooltip-hide {
 	opacity: 0;
 	visibility: hidden;
-	animation: tooltip-out 0.5s ease-in-out;
+	animation: rcb-animation-tooltip-out 0.5s ease-in-out;
 }
 
 .rcb-chat-tooltip.rcb-tooltip-show {
 	opacity: 1;
 	visibility: visible;
-	animation: tooltip-in 0.5s ease-in-out;
-}
-
-@keyframes tooltip-in {
-	0% {
-	  opacity: 0;
-	  transform: translateY(-5px);
-	}
-	100% {
-	  opacity: 1;
-	  transform: translateY(0);
-	}
-  }
-  
-@keyframes tooltip-out {
-	0% {
-	  opacity: 1;
-	  transform: translateY(0);
-	}
-	100% {
-	  opacity: 0;
-	  transform: translateY(-5px);
-	}
+	animation: rcb-animation-tooltip-in 0.5s ease-in-out;
 }
\ No newline at end of file
diff --git a/src/components/LoadingSpinner/LoadingSpinner.css b/src/components/LoadingSpinner/LoadingSpinner.css
index 4938a3f..7b23a87 100644
--- a/src/components/LoadingSpinner/LoadingSpinner.css
+++ b/src/components/LoadingSpinner/LoadingSpinner.css
@@ -17,14 +17,5 @@
 	height: 22px;
 	border-radius: 50%;
 	border: 4px solid #f3f3f3;
-	animation: rcb-spin 1s linear infinite;
-}
-  
-@keyframes rcb-spin {
-	0% {
-		transform: rotate(0deg);
-	}
-	100% {
-		transform: rotate(360deg);
-	}
+	animation: rcb-animation-spin 1s linear infinite;
 }
\ No newline at end of file
diff --git a/src/hooks/internal/useChatHistoryInternal.ts b/src/hooks/internal/useChatHistoryInternal.ts
index 7101eff..da3022b 100644
--- a/src/hooks/internal/useChatHistoryInternal.ts
+++ b/src/hooks/internal/useChatHistoryInternal.ts
@@ -25,8 +25,6 @@ export const useChatHistoryInternal = () => {
 	const {
 		isLoadingChatHistory,
 		setIsLoadingChatHistory,
-		textAreaDisabled,
-		setTextAreaDisabled
 	} = useBotStatesContext();
 
 	// handles rcb events
@@ -51,10 +49,8 @@ export const useChatHistoryInternal = () => {
 			}
 		}
 		setIsLoadingChatHistory(true);
-		const prevTextAreaDisabled = textAreaDisabled;
-		setTextAreaDisabled(true);
-		loadChatHistory(settings, styles, chatHistory, setMessages, prevTextAreaDisabled, setTextAreaDisabled);
-	}, [settings, styles, setMessages, setTextAreaDisabled]);
+		loadChatHistory(settings, styles, chatHistory, setMessages);
+	}, [settings, styles, setMessages]);
 
 	return { isLoadingChatHistory, setIsLoadingChatHistory, showChatHistory };
 };
diff --git a/src/services/ChatHistoryService.tsx b/src/services/ChatHistoryService.tsx
index bba2112..6c39834 100644
--- a/src/services/ChatHistoryService.tsx
+++ b/src/services/ChatHistoryService.tsx
@@ -128,8 +128,7 @@ const parseMessageToString = (message: Message) => {
  * @param setTextAreaDisabled setter for enabling/disabling user text area
  */
 const loadChatHistory = (settings: Settings, styles: Styles, chatHistory: Message[],
-	setMessages: Dispatch<SetStateAction<Message[]>>, prevTextAreaDisabled: boolean,
-	setTextAreaDisabled: Dispatch<SetStateAction<boolean>>) => {
+	setMessages: Dispatch<SetStateAction<Message[]>>) => {
 
 	historyLoaded = true;
 	if (chatHistory != null) {
@@ -160,7 +159,6 @@ const loadChatHistory = (settings: Settings, styles: Styles, chatHistory: Messag
 					}
 					return [...parsedMessages, lineBreakMessage, ...prevMessages];
 				});
-				setTextAreaDisabled(prevTextAreaDisabled ?? settings.chatInput?.disabled ?? false);
 			}, 500)
 		} catch {
 			// remove chat history on error (to address corrupted storage values)


Test patch:
diff --git a/__tests__/hooks/internal/useChatHistoryInternal.test.ts b/__tests__/hooks/internal/useChatHistoryInternal.test.ts
index 61e33f8..3bace45 100644
--- a/__tests__/hooks/internal/useChatHistoryInternal.test.ts
+++ b/__tests__/hooks/internal/useChatHistoryInternal.test.ts
@@ -27,25 +27,25 @@ describe("useChatHistoryInternal Hook", () => {
 
 	// initial values
 	const initialIsLoadingChatHistory = false;
-    const initialChatHistory = [
-        {
-            id: generateSecureUUID(),
-            sender: "user",
-            content: "Hello",
-            type: "string",
-            timestamp: new Date().toUTCString()
-        },
-        {
-            id: generateSecureUUID(),
-            sender: "bot",
-            content: "Hi there!",
-            type: "string",
-            timestamp: new Date().toUTCString()
-        },
-    ];
+	const initialChatHistory = [
+		{
+			id: generateSecureUUID(),
+			sender: "user",
+			content: "Hello",
+			type: "string",
+			timestamp: new Date().toUTCString()
+		},
+		{
+			id: generateSecureUUID(),
+			sender: "bot",
+			content: "Hi there!",
+			type: "string",
+			timestamp: new Date().toUTCString()
+		},
+	];
 
 	it("should load chat history correctly, change state and emit rcb-load-chat-history event", async () => {
-        // mocks rcb event handler
+		// mocks rcb event handler
 		const callRcbEventMock = jest.fn().mockReturnValue({ defaultPrevented: false });
 		mockUseRcbEventInternal.mockReturnValue({
 			callRcbEvent: callRcbEventMock,
@@ -56,9 +56,8 @@ describe("useChatHistoryInternal Hook", () => {
 
 		// mocks loadChatHistory to resolve successfully
 		mockLoadChatHistory.mockImplementation(
-			(settings, styles, chatHistory, setMessages, prevTextAreaDisabled, setTextAreaDisabled) => {
+			(settings, styles, chatHistory, setMessages) => {
 				setMessages(chatHistory);
-				setTextAreaDisabled(false);
 				return Promise.resolve();
 			}
 		);
@@ -82,20 +81,18 @@ describe("useChatHistoryInternal Hook", () => {
 		// checks if get history messages was called
 		expect(mockGetHistoryMessages).toHaveBeenCalledTimes(1);
 
-        // checks if callRcbEvent was called with rcb-load-chat-history and correct arguments
+		// checks if callRcbEvent was called with rcb-load-chat-history and correct arguments
 		expect(callRcbEventMock).toHaveBeenCalledWith(RcbEvent.LOAD_CHAT_HISTORY, {});
-		
-        // checks if load chat history was called
-        expect(mockLoadChatHistory).toHaveBeenCalledWith(
+
+		// checks if load chat history was called
+		expect(mockLoadChatHistory).toHaveBeenCalledWith(
 			MockDefaultSettings,
 			expect.any(Object),
 			initialChatHistory,
 			expect.any(Function),
-			expect.any(Boolean),
-			expect.any(Function)
 		);
 
-        // checks if history is being loaded
+		// checks if history is being loaded
 		expect(result.current.isLoadingChatHistory).toBe(true);
 	});
 
@@ -125,13 +122,13 @@ describe("useChatHistoryInternal Hook", () => {
 		// checks if get history messages was called
 		expect(mockGetHistoryMessages).toHaveBeenCalledTimes(1);
 
-        // checks if callRcbEvent was called with rcb-load-chat-history and correct arguments
+		// checks if callRcbEvent was called with rcb-load-chat-history and correct arguments
 		expect(callRcbEventMock).toHaveBeenCalledWith(RcbEvent.LOAD_CHAT_HISTORY, {});
 
-        // checks if load chat history was not called
+		// checks if load chat history was not called
 		expect(mockLoadChatHistory).not.toHaveBeenCalled();
 
-        // checks if history is being loaded
+		// checks if history is being loaded
 		expect(result.current.isLoadingChatHistory).toBe(false);
 	});
 });
diff --git a/__tests__/services/FunctionProcessor.test.ts b/__tests__/services/FunctionProcessor.test.ts
new file mode 100644
index 0000000..586f6e0
--- /dev/null
+++ b/__tests__/services/FunctionProcessor.test.ts
@@ -0,0 +1,60 @@
+import { processFunction } from "../../src/services/BlockService/FunctionProcessor";
+import { Block } from "../../src/types/Block";
+import { Params } from "../../src/types/Params";
+
+describe('processFunction', () => {
+    let params: Params;
+
+    beforeEach(() => {
+        params = {
+            userInput: "",
+            currPath: null,
+            prevPath: null,
+            goToPath: jest.fn(),
+            setTextAreaValue: jest.fn(),
+            injectMessage: jest.fn(),
+            streamMessage: jest.fn(),
+            removeMessage: jest.fn(),
+            endStreamMessage: jest.fn(),
+            showToast: jest.fn(),
+            dismissToast: jest.fn(),
+            openChat: jest.fn()
+        };
+    });
+
+    it('should return undefined if block has no function', async () => {
+        const block: Block = { function: undefined };
+
+        const result = await processFunction(block, params);
+
+        expect(result).toBeUndefined();
+    });
+
+    it('should return the result of the function if it is not a promise', async () => {
+        const block: Block = { function: jest.fn(() => 'result') };
+
+        const result = await processFunction(block, params);
+
+        expect(result).toBe('result');
+    });
+
+    it('should return the resolved value of the function if it is a promise', async () => {
+        const block: Block = { function: jest.fn(() => Promise.resolve('resolved value')) };
+
+        const result = await processFunction(block, params);
+
+        expect(result).toBe('resolved value');
+    });
+
+    it('should handle function throwing an error', async () => {
+        const block: Block = { function: jest.fn(() => { throw new Error('error'); }) };
+
+        await expect(processFunction(block, params)).rejects.toThrow('error');
+    });
+
+    it('should handle function returning a rejected promise', async () => {
+        const block: Block = { function: jest.fn(() => Promise.reject('rejected value')) };
+
+        await expect(processFunction(block, params)).rejects.toBe('rejected value');
+    });
+});