Skip to content

Commit 7dd46b7

Browse files
authored
Merge pull request #4 from tasbi03/Testing
Added Test-cases InputValidator Plugin
2 parents 9a2b04d + cfe4abc commit 7dd46b7

10 files changed

+4713
-231
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ yarn-error.log*
2828
pnpm-debug.log*
2929
lerna-debug.log*
3030

31+
# coverage
32+
/coverage
33+
3134
# editors
3235
.vscode/*
3336
!.vscode/extensions.json

__tests__/core/useRcbPlugin.test.ts

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
import { renderHook, fireEvent } from "@testing-library/react";
2+
import { validateFile } from "../../src/utils/validateFile";
3+
import { getValidator } from "../../src/utils/getValidator";
4+
import useRcbPlugin from "../../src/core/useRcbPlugin";
5+
6+
const mockReplaceStyles = jest.fn();
7+
const mockShowToast = jest.fn();
8+
9+
// Mock react-chatbotify dependencies
10+
jest.mock("react-chatbotify", () => ({
11+
useToasts: jest.fn(() => ({ showToast: mockShowToast })),
12+
useBotId: jest.fn(() => ({ getBotId: jest.fn().mockReturnValue("bot-id") })),
13+
useFlow: jest.fn(() => ({ getFlow: jest.fn() })),
14+
useStyles: jest.fn(() => ({
15+
styles: {},
16+
updateStyles: jest.fn(),
17+
replaceStyles: mockReplaceStyles,
18+
})),
19+
}));
20+
21+
jest.mock("../../src/utils/validateFile", () => ({
22+
validateFile: jest.fn(),
23+
}));
24+
25+
jest.mock("../../src/utils/getValidator", () => ({
26+
getValidator: jest.fn(),
27+
}));
28+
29+
const mockedValidateFile = validateFile as jest.Mock;
30+
const mockedGetValidator = getValidator as jest.Mock;
31+
32+
mockedValidateFile.mockReturnValue({
33+
success: false,
34+
promptContent: "Invalid file type",
35+
});
36+
37+
mockedGetValidator.mockReturnValue(mockedValidateFile);
38+
39+
// Define custom event interfaces
40+
interface FileUploadEvent extends Event {
41+
data: { files: File[] | null };
42+
}
43+
44+
interface TextInputEvent extends Event {
45+
data: { inputText: string };
46+
}
47+
48+
// Helper functions
49+
const createFileUploadEvent = (files: File[] | null): FileUploadEvent => {
50+
const event = new Event("rcb-user-upload-file") as FileUploadEvent;
51+
event.data = { files };
52+
return event;
53+
};
54+
55+
const createTextInputEvent = (inputText: string): TextInputEvent => {
56+
const event = new Event("rcb-user-submit-text") as TextInputEvent;
57+
event.data = { inputText };
58+
return event;
59+
};
60+
61+
const renderRcbPluginHook = () => renderHook(() => useRcbPlugin());
62+
63+
describe("useRcbPlugin", () => {
64+
beforeEach(() => {
65+
jest.clearAllMocks();
66+
});
67+
68+
describe("File Upload Handling", () => {
69+
describe("Valid and Invalid Files", () => {
70+
test("displays error for invalid file", () => {
71+
const mockFile = new File(["invalid content"], "test.txt", { type: "text/plain" });
72+
mockedValidateFile.mockReturnValue({
73+
success: false,
74+
promptContent: "Invalid file type",
75+
});
76+
77+
renderRcbPluginHook();
78+
const uploadEvent = createFileUploadEvent([mockFile]);
79+
fireEvent(window, uploadEvent);
80+
81+
expect(mockedValidateFile).toHaveBeenCalledWith(mockFile);
82+
expect(mockShowToast).toHaveBeenCalledWith("Invalid file type", 3000);
83+
});
84+
85+
test("does nothing for valid file", () => {
86+
const mockFile = new File(["valid content"], "test.png", { type: "image/png" });
87+
mockedValidateFile.mockReturnValue({ success: true });
88+
89+
renderRcbPluginHook();
90+
const uploadEvent = createFileUploadEvent([mockFile]);
91+
fireEvent(window, uploadEvent);
92+
93+
expect(mockedValidateFile).toHaveBeenCalledWith(mockFile);
94+
expect(mockShowToast).not.toHaveBeenCalled();
95+
});
96+
});
97+
98+
describe("Edge Cases", () => {
99+
test("handles null file upload", () => {
100+
renderRcbPluginHook();
101+
const uploadEvent = createFileUploadEvent(null);
102+
fireEvent(window, uploadEvent);
103+
104+
expect(mockedValidateFile).not.toHaveBeenCalled();
105+
expect(mockShowToast).not.toHaveBeenCalled();
106+
});
107+
108+
test("handles empty file upload", () => {
109+
renderRcbPluginHook();
110+
const uploadEvent = createFileUploadEvent([]);
111+
fireEvent(window, uploadEvent);
112+
113+
expect(mockedValidateFile).not.toHaveBeenCalled();
114+
expect(mockShowToast).not.toHaveBeenCalled();
115+
});
116+
});
117+
});
118+
119+
describe("Text Input Handling", () => {
120+
describe("Valid and Invalid Input", () => {
121+
test("displays error for invalid input", () => {
122+
const mockValidator = jest.fn().mockReturnValue({
123+
success: false,
124+
promptContent: "Invalid input",
125+
});
126+
127+
mockedGetValidator.mockReturnValue(mockValidator);
128+
129+
renderRcbPluginHook();
130+
const textEvent = createTextInputEvent("invalid text");
131+
fireEvent(window, textEvent);
132+
133+
expect(mockValidator).toHaveBeenCalledWith("invalid text");
134+
expect(mockShowToast).toHaveBeenCalledWith("Invalid input", 3000);
135+
});
136+
137+
test("does nothing for valid input", () => {
138+
const mockValidator = jest.fn().mockReturnValue({ success: true });
139+
mockedGetValidator.mockReturnValue(mockValidator);
140+
141+
renderRcbPluginHook();
142+
const textEvent = createTextInputEvent("valid input");
143+
fireEvent(window, textEvent);
144+
145+
expect(mockValidator).toHaveBeenCalledWith("valid input");
146+
expect(mockShowToast).not.toHaveBeenCalled();
147+
});
148+
});
149+
150+
test("displays error for empty text input", () => {
151+
const mockValidator = jest.fn().mockReturnValue({
152+
success: false,
153+
promptContent: "Input cannot be empty",
154+
});
155+
156+
mockedGetValidator.mockReturnValue(mockValidator);
157+
158+
renderRcbPluginHook();
159+
const textEvent = createTextInputEvent("");
160+
fireEvent(window, textEvent);
161+
162+
expect(mockValidator).toHaveBeenCalledWith("");
163+
expect(mockShowToast).toHaveBeenCalledWith("Input cannot be empty", 3000);
164+
});
165+
});
166+
167+
describe("Styles Restoration", () => {
168+
test("restores styles after all toasts are dismissed", () => {
169+
renderRcbPluginHook();
170+
const dismissEvent = new Event("rcb-dismiss-toast");
171+
fireEvent(window, dismissEvent);
172+
173+
setTimeout(() => {
174+
expect(mockReplaceStyles).toHaveBeenCalled();
175+
}, 0);
176+
});
177+
});
178+
});
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
import { getPromptStyles } from "../../src/utils/getPromptStyles";
2+
import { PluginConfig } from "../../src/types/PluginConfig";
3+
4+
test("applies error styles when promptType is 'error'", () => {
5+
const mockPluginConfig: PluginConfig = {
6+
promptBaseColors: {
7+
error: "red",
8+
},
9+
textAreaHighlightColors: {
10+
error: "red",
11+
},
12+
};
13+
14+
const validationResult = {
15+
success: false,
16+
promptType: "error",
17+
highlightTextArea: true,
18+
};
19+
20+
const result = getPromptStyles(validationResult, mockPluginConfig);
21+
22+
// Debugging output to verify the structure of the result
23+
console.log("Result from getPromptStyles:", result);
24+
25+
expect(result).toEqual(
26+
expect.objectContaining({
27+
toastPromptStyle: expect.objectContaining({
28+
color: "red",
29+
borderColor: "red",
30+
}),
31+
chatInputAreaStyle: expect.objectContaining({
32+
boxShadow: "red 0px 0px 5px",
33+
}),
34+
})
35+
);
36+
});
37+
38+
test("applies default styles when promptType is not provided", () => {
39+
const mockPluginConfig: PluginConfig = {
40+
promptBaseColors: {
41+
info: "blue",
42+
},
43+
};
44+
45+
const validationResult = {
46+
success: true, // No promptType provided
47+
};
48+
49+
const result = getPromptStyles(validationResult, mockPluginConfig);
50+
51+
expect(result).toEqual(
52+
expect.objectContaining({
53+
toastPromptStyle: expect.objectContaining({
54+
color: "blue",
55+
borderColor: "blue",
56+
}),
57+
})
58+
);
59+
});
60+
61+
test("applies advancedStyles when available for the promptType", () => {
62+
const mockPluginConfig: PluginConfig = {
63+
advancedStyles: {
64+
error: {
65+
toastPromptStyle: {
66+
backgroundColor: "darkred",
67+
},
68+
},
69+
},
70+
};
71+
72+
const validationResult = {
73+
success: false,
74+
promptType: "error",
75+
};
76+
77+
const result = getPromptStyles(validationResult, mockPluginConfig);
78+
79+
expect(result).toEqual(
80+
expect.objectContaining({
81+
toastPromptStyle: {
82+
backgroundColor: "darkred",
83+
},
84+
})
85+
);
86+
});
87+
88+
test("applies hovered colors when promptHoveredColors is provided", () => {
89+
const mockPluginConfig: PluginConfig = {
90+
promptHoveredColors: {
91+
success: "green",
92+
},
93+
};
94+
95+
const validationResult = {
96+
success: true,
97+
promptType: "success",
98+
};
99+
100+
const result = getPromptStyles(validationResult, mockPluginConfig);
101+
102+
expect(result).toEqual(
103+
expect.objectContaining({
104+
toastPromptHoveredStyle: {
105+
color: "green",
106+
borderColor: "green",
107+
},
108+
})
109+
);
110+
});
111+
112+
test("does not apply chat input highlight when highlightTextArea is false", () => {
113+
const mockPluginConfig: PluginConfig = {
114+
textAreaHighlightColors: {
115+
error: "red",
116+
},
117+
};
118+
119+
const validationResult = {
120+
success: false,
121+
promptType: "error",
122+
highlightTextArea: false,
123+
};
124+
125+
const result = getPromptStyles(validationResult, mockPluginConfig);
126+
127+
expect(result.chatInputAreaStyle).toBeUndefined();
128+
});
129+
test("returns an empty object when pluginConfig is empty", () => {
130+
const mockPluginConfig: PluginConfig = {};
131+
132+
const validationResult = {
133+
success: true,
134+
promptType: "success",
135+
};
136+
137+
const result = getPromptStyles(validationResult, mockPluginConfig);
138+
139+
expect(result).toEqual({});
140+
});
141+

0 commit comments

Comments
 (0)