9deb320cf6
Rename the global Sidebar route, UI, assets, analytics, and payment return context to Profile. Add accessible message-avatar navigation and preserve the source character across auth and logout flows. BREAKING CHANGE: /sidebar has been removed; use /profile instead.
114 lines
2.9 KiB
TypeScript
114 lines
2.9 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
|
|
import type { UserView } from "@/stores/user/user-view";
|
|
|
|
import {
|
|
getProfileViewModel,
|
|
getProfileWalletView,
|
|
normalizeProfileCount,
|
|
} from "../profile-view-model";
|
|
|
|
const baseUser: UserView = {
|
|
id: "user-1",
|
|
username: "Chase",
|
|
countryCode: "US",
|
|
creditBalance: 120,
|
|
dailyFreeChatLimit: 30,
|
|
dailyFreeChatRemaining: 24,
|
|
dailyFreePrivateLimit: 4,
|
|
dailyFreePrivateRemaining: 2,
|
|
isVip: false,
|
|
};
|
|
|
|
describe("getProfileViewModel", () => {
|
|
it("derives guest state for logged-out users", () => {
|
|
const view = getProfileViewModel({
|
|
loginStatus: "notLoggedIn",
|
|
user: {
|
|
currentUser: null,
|
|
avatarUrl: null,
|
|
creditBalance: 0,
|
|
},
|
|
});
|
|
|
|
expect(view.state).toBe("guest");
|
|
expect(view.canActivateVip).toBe(true);
|
|
expect(view.canShowSettings).toBe(false);
|
|
});
|
|
|
|
it("derives member state and shows VIP activation for non-VIP users", () => {
|
|
const view = getProfileViewModel({
|
|
loginStatus: "email",
|
|
user: {
|
|
currentUser: baseUser,
|
|
avatarUrl: "https://example.com/avatar.png",
|
|
creditBalance: 120,
|
|
},
|
|
});
|
|
|
|
expect(view.state).toBe("member");
|
|
expect(view.name).toBe("Chase");
|
|
expect(view.avatarUrl).toBe("https://example.com/avatar.png");
|
|
expect(view.canActivateVip).toBe(true);
|
|
expect(view.canShowSettings).toBe(true);
|
|
});
|
|
|
|
it("derives VIP state and hides VIP activation for VIP users", () => {
|
|
const view = getProfileViewModel({
|
|
loginStatus: "email",
|
|
user: {
|
|
currentUser: { ...baseUser, isVip: true },
|
|
avatarUrl: null,
|
|
creditBalance: 120,
|
|
},
|
|
});
|
|
|
|
expect(view.state).toBe("vip");
|
|
expect(view.canActivateVip).toBe(false);
|
|
});
|
|
|
|
it("keeps Guest users in the signed-out profile state", () => {
|
|
const view = getProfileViewModel({
|
|
loginStatus: "guest",
|
|
user: {
|
|
currentUser: null,
|
|
avatarUrl: null,
|
|
creditBalance: null,
|
|
},
|
|
});
|
|
|
|
expect(view.state).toBe("guest");
|
|
expect(view.name).toBe("User name");
|
|
expect(view.isInitializingUser).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("getProfileWalletView", () => {
|
|
it("normalizes missing, negative, and fractional wallet values", () => {
|
|
const view = getProfileWalletView({
|
|
currentUser: {
|
|
...baseUser,
|
|
dailyFreeChatLimit: -1,
|
|
dailyFreeChatRemaining: 12.9,
|
|
dailyFreePrivateLimit: Number.NaN,
|
|
dailyFreePrivateRemaining: 3.7,
|
|
},
|
|
avatarUrl: null,
|
|
creditBalance: -42.8,
|
|
});
|
|
|
|
expect(view).toEqual({
|
|
creditBalance: 0,
|
|
dailyFreeChatLimit: 0,
|
|
dailyFreeChatRemaining: 12,
|
|
dailyFreePrivateLimit: 0,
|
|
dailyFreePrivateRemaining: 3,
|
|
});
|
|
});
|
|
|
|
it("normalizes undefined and null counts to zero", () => {
|
|
expect(normalizeProfileCount(undefined)).toBe(0);
|
|
expect(normalizeProfileCount(null)).toBe(0);
|
|
});
|
|
});
|