import { renderToStaticMarkup } from "react-dom/server";
import { describe, expect, it, vi } from "vitest";
import { BrowserHintOverlay } from "../browser-hint-overlay";
import { ChatHeader } from "../chat-header";
import { ChatInsufficientCreditsBanner } from "../chat-insufficient-credits-banner";
import { ChatInputTextField } from "../chat-input-text-field";
import { ChatSendButton } from "../chat-send-button";
import { HistoryUnlockDialog } from "../history-unlock-dialog";
import { ImageBubble } from "../image-bubble";
import { InsufficientCreditsDialog } from "../insufficient-credits-dialog";
import { MessageAvatar } from "../message-avatar";
import { PrivateMessageCard } from "../private-message-card";
import { PwaInstallDialog } from "../pwa-install-dialog";
import { TextBubble } from "../text-bubble";
vi.mock("@/router/use-app-navigator", () => ({
useAppNavigator: () => ({
openSubscription: vi.fn(),
}),
}));
describe("chat Tailwind components", () => {
it("renders MessageAvatar AI and user branches with image utilities", () => {
const aiHtml = renderToStaticMarkup();
const userHtml = renderToStaticMarkup(
,
);
expect(aiHtml).toContain('aria-label="AI avatar"');
expect(aiHtml).toContain("size-(--chat-avatar-size,43px)");
expect(aiHtml).toContain("size-full object-cover");
expect(aiHtml).toContain("%2Fimages%2Favatar%2Felio.png");
expect(userHtml).toContain('aria-label="User avatar"');
expect(userHtml).toContain("%2Fuser-avatar.png");
});
it("renders TextBubble AI and user visual variants", () => {
const aiHtml = renderToStaticMarkup(
,
);
const userHtml = renderToStaticMarkup(
,
);
expect(aiHtml).toContain("whitespace-pre-wrap");
expect(aiHtml).toContain("rounded-tl-none");
expect(aiHtml).toContain("bg-white");
expect(aiHtml).toContain("hello\nthere");
expect(userHtml).toContain("rounded-tr-none");
expect(userHtml).toContain(
"bg-[linear-gradient(to_right,var(--color-button-gradient-start,#ff67e0),var(--color-button-gradient-end,#ff52a2))]",
);
expect(userHtml).toContain("from user");
});
it("renders PrivateMessageCard with fallback and loading states", () => {
const fallbackHtml = renderToStaticMarkup();
const unlockingHtml = renderToStaticMarkup(
undefined} />,
);
expect(fallbackHtml).toContain('role="group"');
expect(fallbackHtml).toContain('aria-label="Locked private message"');
expect(fallbackHtml).toContain("rounded-tl-none");
expect(fallbackHtml).toContain("Elio has a private message for you.");
expect(fallbackHtml).toContain("disabled");
expect(unlockingHtml).toContain("Premium secret");
expect(unlockingHtml).toContain("Unlocking...");
});
it("renders ChatSendButton visual states", () => {
const activeHtml = renderToStaticMarkup(
undefined}
onPointerDownSend={() => undefined}
/>,
);
const emptyHtml = renderToStaticMarkup(
undefined}
onPointerDownSend={() => undefined}
/>,
);
const disabledHtml = renderToStaticMarkup(
undefined}
onPointerDownSend={() => undefined}
/>,
);
expect(activeHtml).toContain('aria-label="Send message"');
expect(activeHtml).toContain('data-analytics-ignore="true"');
expect(activeHtml).not.toContain("data-analytics-key");
expect(activeHtml).toContain("size-(--chat-send-button-size,40px)");
expect(activeHtml).toContain(
"bg-[linear-gradient(to_right,var(--color-button-gradient-start,#ff67e0),var(--color-button-gradient-end,#ff52a2))]",
);
expect(emptyHtml).toContain("bg-[#f8a8ce]");
expect(emptyHtml).toContain("text-[rgba(255,255,255,0.88)]");
expect(disabledHtml).toContain("disabled");
});
it("renders ImageBubble openable and paywalled states", () => {
const openableHtml = renderToStaticMarkup(
undefined}
/>,
);
const paywalledHtml = renderToStaticMarkup(
,
);
expect(openableHtml).toContain('role="button"');
expect(openableHtml).toContain('tabindex="0"');
expect(openableHtml).toContain('aria-label="Open image in fullscreen"');
expect(openableHtml).toContain("rounded-tl-none");
expect(openableHtml).toContain("block h-auto w-full object-cover");
expect(openableHtml).toContain("data:image/png;base64,/chat-image.png");
expect(paywalledHtml).toContain("scale-104 blur-sm");
expect(paywalledHtml).toContain(
"bg-[linear-gradient(180deg,rgba(255,255,255,0.04)_0%,rgba(255,255,255,0.14)_100%)]",
);
expect(paywalledHtml).toContain("data:image/png;base64,/locked-image.png");
});
it("renders ChatInsufficientCreditsBanner with split title and CTA", () => {
const html = renderToStaticMarkup(
undefined}
/>,
);
expect(html).toContain('role="status"');
expect(html).toContain('aria-live="polite"');
expect(html).toContain("Need credits");
expect(html).toContain("
");
expect(html).toContain("Top up now");
expect(html).toContain("Credits keep the conversation going.");
expect(html).toContain('aria-label="Top up"');
expect(html).toContain("bg-[linear-gradient(135deg,#f96ade_0%,#f657a0_100%)]");
expect(html).toContain("active:scale-98");
});
it("renders ChatHeader guest and member branches", () => {
const guestHtml = renderToStaticMarkup();
const memberHtml = renderToStaticMarkup(
Offer} />,
);
const memberWithHintHtml = renderToStaticMarkup(
,
);
const guestWithHintHtml = renderToStaticMarkup(
,
);
expect(guestHtml).toContain('aria-label="Sign up to unlock more features"');
expect(guestHtml).toContain("bg-accent");
expect(guestHtml).toContain("size-(--icon-size-sm,16px)");
expect(guestHtml).not.toContain('href="/splash"');
expect(guestHtml).not.toContain('aria-label="Back to home"');
expect(guestHtml).not.toContain('aria-label="Menu"');
expect(memberHtml).toContain("Offer");
expect(memberHtml).toContain('href="/splash"');
expect(memberHtml).toContain('aria-label="Back to home"');
expect(memberHtml).toContain('aria-label="Menu"');
expect(memberHtml).toContain('data-analytics-key="chat.open_menu"');
expect(memberHtml).toContain('data-analytics-key="chat.back_to_home"');
expect(memberHtml).toContain("bg-[rgba(13,11,20,0.7)]");
expect(memberHtml).toContain("size-(--responsive-icon-button-size,42px)");
expect(memberWithHintHtml).toContain(
'data-analytics-key="chat.external_browser_hint"',
);
expect(memberWithHintHtml).toContain(
"grid-cols-[auto_minmax(0,1fr)_auto]",
);
expect(memberWithHintHtml.indexOf('aria-label="Back to home"')).toBeLessThan(
memberWithHintHtml.indexOf(
'data-analytics-key="chat.external_browser_hint"',
),
);
expect(
memberWithHintHtml.indexOf(
'data-analytics-key="chat.external_browser_hint"',
),
).toBeLessThan(memberWithHintHtml.indexOf('aria-label="Menu"'));
expect(guestWithHintHtml).not.toContain(
'data-analytics-key="chat.external_browser_hint"',
);
});
it("renders ChatInputTextField with textarea utilities", () => {
const html = renderToStaticMarkup(
undefined}
onSubmit={() => undefined}
placeholder="Message Elio"
/>,
);
expect(html).toContain("