Submatter/apps/web/components/chat/chat-message-list.test.tsx
varutasu ff01a5f097
Some checks are pending
CI / Lint, type-check, test (push) Waiting to run
Deploy homelab (CT 116) / Deploy to CT 116 (push) Waiting to run
Make workspace Chat durable and ready for source-built deployment
2026-10-29 19:30:20 +00:00

110 lines
3.2 KiB
TypeScript

import { renderToStaticMarkup } from "react-dom/server";
import { describe, expect, it, vi } from "vitest";
import { ChatMessageList } from "./chat-message-list";
const message = {
id: "server",
sequence: "2",
body: "Confirmed",
authorUserId: "user",
createdAt: "2026-01-01",
};
describe("rendered message states", () => {
it("shows a visible sending state and a retry only on failure", () => {
const pending = {
key: "same-key",
body: "Hello",
failed: false,
retry: vi.fn(),
};
const sending = renderToStaticMarkup(
<ChatMessageList messages={[]} pending={[pending]} />,
);
expect(sending).toContain("Sending…");
expect(sending).not.toContain("Retry");
const failed = renderToStaticMarkup(
<ChatMessageList
messages={[]}
pending={[
{
...pending,
failed: true,
error: "Could not send message. Please retry.",
},
]}
/>,
);
expect(failed).toContain('role="alert"');
expect(failed).toContain("Retry");
});
it("renders only the messages supplied by the parent", () => {
const html = renderToStaticMarkup(<ChatMessageList messages={[message]} />);
expect(html).toContain("Confirmed");
expect(html).not.toContain("Sending…");
expect(html).not.toContain("Retry");
const empty = renderToStaticMarkup(<ChatMessageList messages={[]} />);
expect(empty).not.toContain("Confirmed");
});
it("shows an edited indicator for edited messages", () => {
const html = renderToStaticMarkup(
<ChatMessageList messages={[{ ...message, editedAt: "2026-01-02" }]} />,
);
expect(html).toContain("(edited)");
});
it("only offers owner edit, owner or moderator delete, and never archived or deleted controls", () => {
const own = renderToStaticMarkup(
<ChatMessageList
messages={[message]}
currentUserId="user"
onEdit={vi.fn()}
onDelete={vi.fn()}
/>,
);
expect(own).toContain("Edit message server");
expect(own).toContain("Delete message server");
const moderator = renderToStaticMarkup(
<ChatMessageList
messages={[message]}
currentUserId="moderator"
canModerate
onEdit={vi.fn()}
onDelete={vi.fn()}
/>,
);
expect(moderator).not.toContain("Edit message server");
expect(moderator).toContain("Delete message server");
const archived = renderToStaticMarkup(
<ChatMessageList
messages={[message]}
currentUserId="user"
readOnly
onEdit={vi.fn()}
onDelete={vi.fn()}
/>,
);
expect(archived).not.toContain("Edit message server");
const deleted = renderToStaticMarkup(
<ChatMessageList
messages={[{ ...message, status: "deleted" }]}
currentUserId="user"
onEdit={vi.fn()}
onDelete={vi.fn()}
/>,
);
expect(deleted).not.toContain("Delete message server");
});
it("renders deleted messages as a placeholder instead of their body", () => {
const html = renderToStaticMarkup(
<ChatMessageList messages={[{ ...message, deletedAt: "2026-01-02" }]} />,
);
expect(html).toContain("Message deleted");
expect(html).not.toContain("Confirmed");
});
});