Skip to content

Commit

Permalink
Merge branch 'PSL-US-9859-UT' of https://github.com/microsoft/Documen…
Browse files Browse the repository at this point in the history
  • Loading branch information
Kiran-Siluveru-Microsoft committed Jan 3, 2025
2 parents c10d895 + e1ee3a0 commit 5657127
Show file tree
Hide file tree
Showing 2 changed files with 169 additions and 133 deletions.
268 changes: 152 additions & 116 deletions App/frontend-app/src/components/chat/FeedBackForm.test.tsx
Original file line number Diff line number Diff line change
@@ -1,126 +1,162 @@
import { render, fireEvent, screen, waitFor } from "@testing-library/react";
import { FeedbackForm } from "./FeedbackForm";
import { PostFeedback } from "../../api/chatService";
import { useTranslation } from "react-i18next";
import { Dialog } from "@fluentui/react-components";

// Mocking external dependencies
jest.mock("../../api/chatService", () => ({
PostFeedback: jest.fn(),
PostFeedback: jest.fn(),
}));

jest.mock("react-i18next", () => ({
useTranslation: jest.fn().mockReturnValue({
t: (key: string) => key,
}),
useTranslation: () => ({
t: (key: string) => key,
}),
}));

describe("FeedbackForm", () => {
const defaultProps = {
history: [],
chatOptions: {},
sources: [],
filterByDocumentIds: [],
isOpen: true,
onClose: jest.fn(),
setSubmittedFeedback: jest.fn(),
};

it("renders the feedback form", () => {
render(<FeedbackForm {...defaultProps} />);
expect(screen.getByText("components.feedback-form.title")).toBeInTheDocument();
});

it("shows validation error when reason is not selected", async () => {
render(<FeedbackForm {...defaultProps} />);
fireEvent.click(screen.getByText("components.feedback-form.submit"));
expect(await screen.findByText("components.feedback-form.required-fields")).toBeInTheDocument();
});

it("submits feedback when valid data is entered", async () => {
const submitFeedbackMock = PostFeedback as jest.Mock;
submitFeedbackMock.mockResolvedValueOnce({});

render(<FeedbackForm {...defaultProps} />);

fireEvent.click(screen.getByLabelText("Search Result")); // Selecting a reason
fireEvent.click(screen.getByText("components.feedback-form.submit"));

await waitFor(() => expect(submitFeedbackMock).toHaveBeenCalledTimes(1));
expect(defaultProps.onClose).toHaveBeenCalled();
});

it("handles submission error gracefully", async () => {
const submitFeedbackMock = PostFeedback as jest.Mock;
submitFeedbackMock.mockRejectedValueOnce(new Error("Submission error"));

render(<FeedbackForm {...defaultProps} />);

fireEvent.click(screen.getByLabelText("Search Result"));
fireEvent.click(screen.getByText("components.feedback-form.submit"));

await waitFor(() => expect(screen.getByText("components.feedback-form.feedback-error")).toBeInTheDocument());
});

// it.only("adds and removes document URL fields dynamically", () => {
// render(<FeedbackForm {...defaultProps} />);
// const addButton = screen.getByLabelText("Add Circle Icon"); // Adjust based on actual button icon label
// const removeButton = screen.getByLabelText("Subtract Circle Icon");

// fireEvent.click(addButton); // Add a document URL field
// expect(screen.getAllByPlaceholderText("components.feedback-form.text-area-placeholder")).toHaveLength(2);

// fireEvent.click(removeButton); // Remove a document URL field
// expect(screen.getAllByPlaceholderText("components.feedback-form.text-area-placeholder")).toHaveLength(1);
// });
it("adds and removes document URL fields dynamically", () => {
render(<FeedbackForm {...defaultProps} />);

// Use getByLabelText with the aria-labels from the Button components
const addButton = screen.getByLabelText('Close'); // Make sure this matches the aria-label in your component
const removeButton = screen.getByLabelText('Subtract Circle Icon'); // Same for this aria-label

// Initially, there should be one document URL field
expect(screen.getAllByPlaceholderText("components.feedback-form.text-area-placeholder")).toHaveLength(1);

// Click on the add button to add a document URL field
fireEvent.click(addButton);

// Now, there should be two document URL fields
expect(screen.getAllByPlaceholderText("components.feedback-form.text-area-placeholder")).toHaveLength(2);

// Click on the remove button to remove a document URL field
fireEvent.click(removeButton);

// Now, there should be one document URL field again
expect(screen.getAllByPlaceholderText("components.feedback-form.text-area-placeholder")).toHaveLength(1);
});
it("adds and removes chunk text fields dynamically", () => {
render(<FeedbackForm {...defaultProps} />);
const addButton = screen.getByLabelText("Add Circle Icon"); // Adjust based on actual button icon label
const removeButton = screen.getByLabelText("Subtract Circle Icon");

fireEvent.click(addButton); // Add a chunk text field
expect(screen.getAllByPlaceholderText("components.feedback-form.chunk-texts-placeholder")).toHaveLength(2);

fireEvent.click(removeButton); // Remove a chunk text field
expect(screen.getAllByPlaceholderText("components.feedback-form.chunk-texts-placeholder")).toHaveLength(1);
});

it("shows advanced feedback fields when positive feedback is selected", () => {
render(<FeedbackForm {...defaultProps} />);

const checkbox = screen.getByLabelText("components.feedback-form.advanced-feedback-title");
fireEvent.click(checkbox);

expect(screen.getByLabelText("components.feedback-form.ground-truth-title")).toBeInTheDocument();
expect(screen.getByLabelText("components.feedback-form.doc-urls")).toBeInTheDocument();
expect(screen.getByLabelText("components.feedback-form.chunk-texts-title")).toBeInTheDocument();
});

it("calls onClose when the form is closed", () => {
render(<FeedbackForm {...defaultProps} />);
fireEvent.click(screen.getByLabelText("Close"));
expect(defaultProps.onClose).toHaveBeenCalled();
});
});
describe("FeedbackForm Component", () => {
const mockOnClose = jest.fn();
const mockSetSubmittedFeedback = jest.fn();

const defaultProps = {
history: [],
chatOptions: {},
sources: [],
filterByDocumentIds: [],
isOpen: true,
onClose: mockOnClose,
setSubmittedFeedback: mockSetSubmittedFeedback,
};

it("renders the form correctly when isOpen is true", () => {
render(<FeedbackForm {...defaultProps} />);
expect(screen.getByText("components.feedback-form.submit")).toBeInTheDocument();
});

it("calls onClose when the close button is clicked", () => {
render(<FeedbackForm {...defaultProps} />);
const closeButton = screen.getByLabelText("Close");
fireEvent.click(closeButton);
expect(mockOnClose).toHaveBeenCalled();
});

it("displays a validation error when no reason is selected", () => {
render(<FeedbackForm {...defaultProps} />);
const submitButton = screen.getByText("components.feedback-form.submit");
fireEvent.click(submitButton);
expect(screen.getByText("components.feedback-form.required-fields")).toBeInTheDocument();
});

it("submits the feedback successfully when all fields are valid", async () => {
(PostFeedback as jest.Mock).mockResolvedValueOnce(true);

render(<FeedbackForm {...defaultProps} />);
const radioOption = screen.getByLabelText("Search Result");
fireEvent.click(radioOption);

const commentInput = screen.getByPlaceholderText("components.feedback-form.leave-comment");
fireEvent.change(commentInput, { target: { value: "This is a comment." } });

const submitButton = screen.getByText("components.feedback-form.submit");
fireEvent.click(submitButton);

await waitFor(() => {
expect(PostFeedback).toHaveBeenCalledWith(
expect.objectContaining({
isPositive: false,
reason: "Search Result",
comment: "This is a comment.",
})
);
});
expect(mockOnClose).toHaveBeenCalled();
});

it("handles errors during feedback submission", async () => {
(PostFeedback as jest.Mock).mockRejectedValueOnce(new Error("Network error"));

render(<FeedbackForm {...defaultProps} />);
const radioOption = screen.getByLabelText("Answer");
fireEvent.click(radioOption);

const submitButton = screen.getByText("components.feedback-form.submit");
fireEvent.click(submitButton);

await waitFor(() => {
expect(screen.getByText("components.feedback-form.feedback-error")).toBeInTheDocument();
});
});

it("renders advanced feedback fields when isPositive is true", () => {
render(<FeedbackForm {...defaultProps} />);
const checkbox = screen.getByLabelText("components.feedback-form.advanced-feedback-title");
fireEvent.click(checkbox);

expect(screen.getByLabelText("components.feedback-form.ground-truth-title")).toBeInTheDocument();
expect(screen.getByLabelText("components.feedback-form.doc-urls")).toBeInTheDocument();
expect(screen.getByLabelText("components.feedback-form.chunk-texts-title")).toBeInTheDocument();
});

it("updates advanced feedback fields correctly", () => {
render(<FeedbackForm {...defaultProps} />);
const checkbox = screen.getByLabelText("components.feedback-form.advanced-feedback-title");
fireEvent.click(checkbox);

const groundTruthInput = screen.getByPlaceholderText("components.feedback-form.ground-truth-placeholder") as HTMLInputElement;
fireEvent.change(groundTruthInput, { target: { value: "Ground Truth Example" } });
expect((groundTruthInput as HTMLInputElement).value).toBe("Ground Truth Example");

const docURLInput = screen.getByPlaceholderText("components.feedback-form.text-area-placeholder") as HTMLInputElement;
fireEvent.change(docURLInput, { target: { value: "http://example.com" } });
expect((docURLInput as HTMLInputElement).value).toBe("http://example.com");

const chunkTextInput = screen.getByPlaceholderText("components.feedback-form.chunk-texts-placeholder");
fireEvent.change(chunkTextInput, { target: { value: "Chunk Text Example" } });
expect((chunkTextInput as HTMLInputElement).value).toBe("Chunk Text Example");
});

it("prevents removing the last chunk text or document URL field", () => {
render(<FeedbackForm {...defaultProps} />);

const removeChunkButton = screen.queryByLabelText("Subtract Circle Icon");
if (removeChunkButton) {
fireEvent.click(removeChunkButton);
}
expect(screen.getAllByPlaceholderText("components.feedback-form.chunk-texts-placeholder").length).toBe(1);

const removeDocButton = screen.queryByLabelText("Subtract Circle Icon");
if (removeDocButton) {
fireEvent.click(removeDocButton);
}
expect(screen.getAllByPlaceholderText("components.feedback-form.text-area-placeholder").length).toBe(1);
});

it("submits feedback with advanced fields filled", async () => {
(PostFeedback as jest.Mock).mockResolvedValueOnce(true);

render(<FeedbackForm {...defaultProps} />);
const checkbox = screen.getByLabelText("components.feedback-form.advanced-feedback-title");
fireEvent.click(checkbox);

const groundTruthInput = screen.getByPlaceholderText("components.feedback-form.ground-truth-placeholder");
fireEvent.change(groundTruthInput, { target: { value: "Ground Truth Example" } });

const docURLInput = screen.getByPlaceholderText("components.feedback-form.text-area-placeholder");
fireEvent.change(docURLInput, { target: { value: "http://example.com" } });

const chunkTextInput = screen.getByPlaceholderText("components.feedback-form.chunk-texts-placeholder");
fireEvent.change(chunkTextInput, { target: { value: "Chunk Text Example" } });

const submitButton = screen.getByText("components.feedback-form.submit");
fireEvent.click(submitButton);

await waitFor(() => {
expect(PostFeedback).toHaveBeenCalledWith(
expect.objectContaining({
groundTruthAnswer: "Ground Truth Example",
documentURLs: ["http://example.com"],
chunkTexts: ["Chunk Text Example"],
})
);
});
expect(mockOnClose).toHaveBeenCalled();
});
});
34 changes: 17 additions & 17 deletions App/frontend-app/src/components/searchBox/searchBox.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -377,24 +377,24 @@ describe("SearchBox", () => {
expect(window.alert).toHaveBeenCalledWith("Error uploading files");
});

it("does nothing if no files are selected", async () => {
// Ensure the file input has no files
it("does nothing if no files are selected", () => {
render(<SearchBox onSearchChanged={mockOnSearchChanged} />);

const uploadDiv = screen.getByTestId("upload-div");

const fileInput = document.createElement("input");
fileInput.type = "file";
Object.defineProperty(fileInput, "files", {
value: [],
value: [],
writable: false,
});

// Render the UploadButton
render(<UploadButton />);
const uploadButton = document.querySelector(".upload_button");

// Simulate the file input click
fireEvent.click(uploadButton!);

// Simulate calling uploadDocuments manually
const uploadDocumentsFn = UploadButton.prototype.uploadDocuments;
await uploadDocumentsFn();

// Assert no API call is made

document.body.appendChild(fileInput); // Add to DOM
fireEvent.change(fileInput); // Trigger file selection event

expect(UploadMultipleFiles).not.toHaveBeenCalled();
});

fileInput.remove(); // Cleanup
});

});

0 comments on commit 5657127

Please sign in to comment.