feat(chat): show user avatar in profile action

Render the stored user avatar in the Chat Header when available while preserving the existing Profile icon fallback, navigation, accessibility label, and analytics.
This commit is contained in:
2026-07-21 18:36:45 +08:00
parent 9fff5b16fd
commit 7f271ef2e0
2 changed files with 57 additions and 18 deletions
@@ -1,6 +1,6 @@
import type { ReactNode } from "react";
import { renderToStaticMarkup } from "react-dom/server";
import { describe, expect, it, vi } from "vitest";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { getCharacterBySlug } from "@/data/constants/character";
import { CharacterProvider } from "@/providers/character-provider";
@@ -18,13 +18,27 @@ import { PrivateMessageCard } from "../private-message-card";
import { PwaInstallDialog } from "../pwa-install-dialog";
import { TextBubble } from "../text-bubble";
const userMocks = vi.hoisted(() => ({
avatarUrl: null as string | null,
}));
vi.mock("@/router/use-app-navigator", () => ({
useAppNavigator: () => ({
openSubscription: vi.fn(),
}),
}));
vi.mock("@/stores/user/user-context", () => ({
useUserSelector: (
selector: (state: { context: { avatarUrl: string | null } }) => unknown,
) => selector({ context: { avatarUrl: userMocks.avatarUrl } }),
}));
describe("chat Tailwind components", () => {
beforeEach(() => {
userMocks.avatarUrl = null;
});
it("renders MessageAvatar AI and user branches with image utilities", () => {
const aiHtml = renderWithCharacter(<MessageAvatar isFromAI={true} />);
const userHtml = renderWithCharacter(
@@ -228,6 +242,7 @@ describe("chat Tailwind components", () => {
expect(memberHtml).not.toContain("px-(--spacing-md,12px)");
expect(memberHtml).toContain("bg-[rgba(13,11,20,0.7)]");
expect(memberHtml).toContain("size-(--responsive-icon-button-size,42px)");
expect(memberHtml).toContain("lucide-user-round");
expect(memberWithHintHtml).toContain(
'data-analytics-key="chat.external_browser_hint"',
);
@@ -249,6 +264,20 @@ describe("chat Tailwind components", () => {
);
});
it("renders the user avatar in the ChatHeader Profile action", () => {
userMocks.avatarUrl = "/images/avatar/profile-user.png";
const html = renderWithCharacter(<ChatHeader isGuest={false} />);
expect(html).toContain("%2Fimages%2Favatar%2Fprofile-user.png");
expect(html).toContain('aria-label="Profile"');
expect(html).toContain('data-analytics-key="chat.open_profile"');
expect(html).toContain(
"var(--responsive-icon-button-size, 42px)",
);
expect(html).not.toContain("lucide-user-round");
});
it("links guest chat back to the active character splash", () => {
const maya = getCharacterBySlug("maya");
if (!maya) throw new Error("Missing Maya character fixture");