Skip to content

Added Test-cases InputValidator Plugin #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

# coverage
/coverage

# editors
.vscode/*
!.vscode/extensions.json
Expand Down
178 changes: 178 additions & 0 deletions __tests__/core/useRcbPlugin.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
import { renderHook, fireEvent } from "@testing-library/react";
import { validateFile } from "../../src/utils/validateFile";
import { getValidator } from "../../src/utils/getValidator";
import useRcbPlugin from "../../src/core/useRcbPlugin";

const mockReplaceStyles = jest.fn();
const mockShowToast = jest.fn();

// Mock react-chatbotify dependencies
jest.mock("react-chatbotify", () => ({
useToasts: jest.fn(() => ({ showToast: mockShowToast })),
useBotId: jest.fn(() => ({ getBotId: jest.fn().mockReturnValue("bot-id") })),
useFlow: jest.fn(() => ({ getFlow: jest.fn() })),
useStyles: jest.fn(() => ({
styles: {},
updateStyles: jest.fn(),
replaceStyles: mockReplaceStyles,
})),
}));

jest.mock("../../src/utils/validateFile", () => ({
validateFile: jest.fn(),
}));

jest.mock("../../src/utils/getValidator", () => ({
getValidator: jest.fn(),
}));

const mockedValidateFile = validateFile as jest.Mock;
const mockedGetValidator = getValidator as jest.Mock;

mockedValidateFile.mockReturnValue({
success: false,
promptContent: "Invalid file type",
});

mockedGetValidator.mockReturnValue(mockedValidateFile);

// Define custom event interfaces
interface FileUploadEvent extends Event {
data: { files: File[] | null };
}

interface TextInputEvent extends Event {
data: { inputText: string };
}

// Helper functions
const createFileUploadEvent = (files: File[] | null): FileUploadEvent => {
const event = new Event("rcb-user-upload-file") as FileUploadEvent;
event.data = { files };
return event;
};

const createTextInputEvent = (inputText: string): TextInputEvent => {
const event = new Event("rcb-user-submit-text") as TextInputEvent;
event.data = { inputText };
return event;
};

const renderRcbPluginHook = () => renderHook(() => useRcbPlugin());

describe("useRcbPlugin", () => {
beforeEach(() => {
jest.clearAllMocks();
});

describe("File Upload Handling", () => {
describe("Valid and Invalid Files", () => {
test("displays error for invalid file", () => {
const mockFile = new File(["invalid content"], "test.txt", { type: "text/plain" });
mockedValidateFile.mockReturnValue({
success: false,
promptContent: "Invalid file type",
});

renderRcbPluginHook();
const uploadEvent = createFileUploadEvent([mockFile]);
fireEvent(window, uploadEvent);

expect(mockedValidateFile).toHaveBeenCalledWith(mockFile);
expect(mockShowToast).toHaveBeenCalledWith("Invalid file type", 3000);
});

test("does nothing for valid file", () => {
const mockFile = new File(["valid content"], "test.png", { type: "image/png" });
mockedValidateFile.mockReturnValue({ success: true });

renderRcbPluginHook();
const uploadEvent = createFileUploadEvent([mockFile]);
fireEvent(window, uploadEvent);

expect(mockedValidateFile).toHaveBeenCalledWith(mockFile);
expect(mockShowToast).not.toHaveBeenCalled();
});
});

describe("Edge Cases", () => {
test("handles null file upload", () => {
renderRcbPluginHook();
const uploadEvent = createFileUploadEvent(null);
fireEvent(window, uploadEvent);

expect(mockedValidateFile).not.toHaveBeenCalled();
expect(mockShowToast).not.toHaveBeenCalled();
});

test("handles empty file upload", () => {
renderRcbPluginHook();
const uploadEvent = createFileUploadEvent([]);
fireEvent(window, uploadEvent);

expect(mockedValidateFile).not.toHaveBeenCalled();
expect(mockShowToast).not.toHaveBeenCalled();
});
});
});

describe("Text Input Handling", () => {
describe("Valid and Invalid Input", () => {
test("displays error for invalid input", () => {
const mockValidator = jest.fn().mockReturnValue({
success: false,
promptContent: "Invalid input",
});

mockedGetValidator.mockReturnValue(mockValidator);

renderRcbPluginHook();
const textEvent = createTextInputEvent("invalid text");
fireEvent(window, textEvent);

expect(mockValidator).toHaveBeenCalledWith("invalid text");
expect(mockShowToast).toHaveBeenCalledWith("Invalid input", 3000);
});

test("does nothing for valid input", () => {
const mockValidator = jest.fn().mockReturnValue({ success: true });
mockedGetValidator.mockReturnValue(mockValidator);

renderRcbPluginHook();
const textEvent = createTextInputEvent("valid input");
fireEvent(window, textEvent);

expect(mockValidator).toHaveBeenCalledWith("valid input");
expect(mockShowToast).not.toHaveBeenCalled();
});
});

test("displays error for empty text input", () => {
const mockValidator = jest.fn().mockReturnValue({
success: false,
promptContent: "Input cannot be empty",
});

mockedGetValidator.mockReturnValue(mockValidator);

renderRcbPluginHook();
const textEvent = createTextInputEvent("");
fireEvent(window, textEvent);

expect(mockValidator).toHaveBeenCalledWith("");
expect(mockShowToast).toHaveBeenCalledWith("Input cannot be empty", 3000);
});
});

describe("Styles Restoration", () => {
test("restores styles after all toasts are dismissed", () => {
renderRcbPluginHook();
const dismissEvent = new Event("rcb-dismiss-toast");
fireEvent(window, dismissEvent);

setTimeout(() => {
expect(mockReplaceStyles).toHaveBeenCalled();
}, 0);
});
});
});
141 changes: 141 additions & 0 deletions __tests__/utils/getPromptStyles.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import { getPromptStyles } from "../../src/utils/getPromptStyles";
import { PluginConfig } from "../../src/types/PluginConfig";

test("applies error styles when promptType is 'error'", () => {
const mockPluginConfig: PluginConfig = {
promptBaseColors: {
error: "red",
},
textAreaHighlightColors: {
error: "red",
},
};

const validationResult = {
success: false,
promptType: "error",
highlightTextArea: true,
};

const result = getPromptStyles(validationResult, mockPluginConfig);

// Debugging output to verify the structure of the result
console.log("Result from getPromptStyles:", result);

expect(result).toEqual(
expect.objectContaining({
toastPromptStyle: expect.objectContaining({
color: "red",
borderColor: "red",
}),
chatInputAreaStyle: expect.objectContaining({
boxShadow: "red 0px 0px 5px",
}),
})
);
});

test("applies default styles when promptType is not provided", () => {
const mockPluginConfig: PluginConfig = {
promptBaseColors: {
info: "blue",
},
};

const validationResult = {
success: true, // No promptType provided
};

const result = getPromptStyles(validationResult, mockPluginConfig);

expect(result).toEqual(
expect.objectContaining({
toastPromptStyle: expect.objectContaining({
color: "blue",
borderColor: "blue",
}),
})
);
});

test("applies advancedStyles when available for the promptType", () => {
const mockPluginConfig: PluginConfig = {
advancedStyles: {
error: {
toastPromptStyle: {
backgroundColor: "darkred",
},
},
},
};

const validationResult = {
success: false,
promptType: "error",
};

const result = getPromptStyles(validationResult, mockPluginConfig);

expect(result).toEqual(
expect.objectContaining({
toastPromptStyle: {
backgroundColor: "darkred",
},
})
);
});

test("applies hovered colors when promptHoveredColors is provided", () => {
const mockPluginConfig: PluginConfig = {
promptHoveredColors: {
success: "green",
},
};

const validationResult = {
success: true,
promptType: "success",
};

const result = getPromptStyles(validationResult, mockPluginConfig);

expect(result).toEqual(
expect.objectContaining({
toastPromptHoveredStyle: {
color: "green",
borderColor: "green",
},
})
);
});

test("does not apply chat input highlight when highlightTextArea is false", () => {
const mockPluginConfig: PluginConfig = {
textAreaHighlightColors: {
error: "red",
},
};

const validationResult = {
success: false,
promptType: "error",
highlightTextArea: false,
};

const result = getPromptStyles(validationResult, mockPluginConfig);

expect(result.chatInputAreaStyle).toBeUndefined();
});
test("returns an empty object when pluginConfig is empty", () => {
const mockPluginConfig: PluginConfig = {};

const validationResult = {
success: true,
promptType: "success",
};

const result = getPromptStyles(validationResult, mockPluginConfig);

expect(result).toEqual({});
});

Loading
Loading