Add tests for polishing replies

This commit is contained in:
Moshfegh Hamedani 2026-02-25 12:02:06 -08:00
parent 6f3db062c1
commit caddd8e0a0

View file

@ -21,34 +21,42 @@ function renderForm() {
} }
describe("ReplyForm", () => { describe("ReplyForm", () => {
it("should render textarea and submit button", () => { it("should render textarea, Polish button, and Send Reply button", () => {
renderForm(); renderForm();
expect(screen.getByPlaceholderText("Type your reply...")).toBeInTheDocument(); expect(screen.getByPlaceholderText("Type your reply...")).toBeInTheDocument();
expect(screen.getByRole("button", { name: "Polish" })).toBeInTheDocument();
expect(screen.getByRole("button", { name: "Send Reply" })).toBeInTheDocument(); expect(screen.getByRole("button", { name: "Send Reply" })).toBeInTheDocument();
}); });
it("should show validation error when submitting empty body", async () => { it("should disable Send Reply button when textarea is empty", () => {
const { user } = renderForm(); renderForm();
await user.click(screen.getByRole("button", { name: "Send Reply" })); expect(screen.getByRole("button", { name: "Send Reply" })).toBeDisabled();
await waitFor(() => {
expect(screen.getByText("Reply body is required")).toBeInTheDocument();
});
expect(mockedAxios.post).not.toHaveBeenCalled();
}); });
it("should show validation error for whitespace-only body", async () => { it("should disable Polish button when textarea is empty", () => {
renderForm();
expect(screen.getByRole("button", { name: "Polish" })).toBeDisabled();
});
it("should enable both buttons when text is entered", async () => {
const { user } = renderForm();
await user.type(screen.getByPlaceholderText("Type your reply..."), "Hello");
expect(screen.getByRole("button", { name: "Send Reply" })).toBeEnabled();
expect(screen.getByRole("button", { name: "Polish" })).toBeEnabled();
});
it("should disable both buttons when text is only whitespace", async () => {
const { user } = renderForm(); const { user } = renderForm();
await user.type(screen.getByPlaceholderText("Type your reply..."), " "); await user.type(screen.getByPlaceholderText("Type your reply..."), " ");
await user.click(screen.getByRole("button", { name: "Send Reply" }));
await waitFor(() => { expect(screen.getByRole("button", { name: "Send Reply" })).toBeDisabled();
expect(screen.getByText("Reply body is required")).toBeInTheDocument(); expect(screen.getByRole("button", { name: "Polish" })).toBeDisabled();
});
expect(mockedAxios.post).not.toHaveBeenCalled();
}); });
it("should call POST /api/tickets/:ticketId/replies with body on valid submit", async () => { it("should call POST /api/tickets/:ticketId/replies with body on valid submit", async () => {
@ -128,3 +136,121 @@ describe("ReplyForm", () => {
expect(screen.queryByRole("alert")).not.toBeInTheDocument(); expect(screen.queryByRole("alert")).not.toBeInTheDocument();
}); });
}); });
describe("ReplyForm - Polish", () => {
it("should call POST /api/tickets/:ticketId/replies/polish with body", async () => {
mockedAxios.post.mockResolvedValue({ data: { body: "Polished text" } });
const { user } = renderForm();
await user.type(screen.getByPlaceholderText("Type your reply..."), "rough draft");
await user.click(screen.getByRole("button", { name: "Polish" }));
await waitFor(() => {
expect(mockedAxios.post).toHaveBeenCalledWith(
`/api/tickets/${TICKET_ID}/replies/polish`,
{ body: "rough draft" }
);
});
});
it("should replace textarea content with polished text on success", async () => {
mockedAxios.post.mockResolvedValue({ data: { body: "Polished text" } });
const { user } = renderForm();
const textarea = screen.getByPlaceholderText("Type your reply...");
await user.type(textarea, "rough draft");
await user.click(screen.getByRole("button", { name: "Polish" }));
await waitFor(() => {
expect(textarea).toHaveValue("Polished text");
});
});
it("should show 'Polishing...' and disable button while polishing", async () => {
mockedAxios.post.mockReturnValue(new Promise(() => {}));
const { user } = renderForm();
await user.type(screen.getByPlaceholderText("Type your reply..."), "Hello");
await user.click(screen.getByRole("button", { name: "Polish" }));
await waitFor(() => {
const button = screen.getByRole("button", { name: "Polishing..." });
expect(button).toBeDisabled();
});
});
it("should disable Send Reply button while polishing", async () => {
mockedAxios.post.mockReturnValue(new Promise(() => {}));
const { user } = renderForm();
await user.type(screen.getByPlaceholderText("Type your reply..."), "Hello");
await user.click(screen.getByRole("button", { name: "Polish" }));
await waitFor(() => {
expect(screen.getByRole("button", { name: "Send Reply" })).toBeDisabled();
});
});
it("should disable Polish button while sending reply", async () => {
mockedAxios.post.mockReturnValue(new Promise(() => {}));
const { user } = renderForm();
await user.type(screen.getByPlaceholderText("Type your reply..."), "Hello");
await user.click(screen.getByRole("button", { name: "Send Reply" }));
await waitFor(() => {
expect(screen.getByRole("button", { name: "Polish" })).toBeDisabled();
});
});
it("should show error when polish request fails", async () => {
mockedAxios.post.mockRejectedValue(new Error("AI service unavailable"));
mockedAxios.isAxiosError.mockReturnValue(false);
const { user } = renderForm();
await user.type(screen.getByPlaceholderText("Type your reply..."), "Hello");
await user.click(screen.getByRole("button", { name: "Polish" }));
await waitFor(() => {
expect(screen.getByText("Failed to polish reply")).toBeInTheDocument();
});
});
it("should not clear textarea when polish fails", async () => {
mockedAxios.post.mockRejectedValue(new Error("AI service unavailable"));
mockedAxios.isAxiosError.mockReturnValue(false);
const { user } = renderForm();
const textarea = screen.getByPlaceholderText("Type your reply...");
await user.type(textarea, "my draft");
await user.click(screen.getByRole("button", { name: "Polish" }));
await waitFor(() => {
expect(screen.getByText("Failed to polish reply")).toBeInTheDocument();
});
expect(textarea).toHaveValue("my draft");
});
it("should allow sending the polished reply", async () => {
mockedAxios.post
.mockResolvedValueOnce({ data: { body: "Polished text" } })
.mockResolvedValueOnce({ data: { id: 1, body: "Polished text" } });
const { user } = renderForm();
await user.type(screen.getByPlaceholderText("Type your reply..."), "rough draft");
await user.click(screen.getByRole("button", { name: "Polish" }));
await waitFor(() => {
expect(screen.getByPlaceholderText("Type your reply...")).toHaveValue("Polished text");
});
await user.click(screen.getByRole("button", { name: "Send Reply" }));
await waitFor(() => {
expect(mockedAxios.post).toHaveBeenCalledWith(
`/api/tickets/${TICKET_ID}/replies`,
{ body: "Polished text" }
);
});
});
});