test(accounts): cover codex free-tier identity labels

This commit is contained in:
Tam Nhu Tran committed 2026-04-14 18:09:23 -04:00
1 parent 32c16a3739
commit d5868e0688
3 files changed
+130 -10

No files matched your search

@@ -20,7 +20,7 @@ vi.mock('@/hooks/use-cliproxy-stats', async () => {
const mockedUseAccountQuota = vi.mocked(useAccountQuota); const mockedUseAccountQuota = vi.mocked(useAccountQuota);
const mockedUseAccountQuotas = vi.mocked(useAccountQuotas); const mockedUseAccountQuotas = vi.mocked(useAccountQuotas);
function makeCodexQuota(planType: 'plus' | 'team', fiveHour: number, weekly: number) { function makeCodexQuota(planType: 'free' | 'plus' | 'team', fiveHour: number, weekly: number) {
return { return {
success: true, success: true,
planType, planType,
@@ -76,7 +76,9 @@ const groupedAccount: AccountData = {
failureCount: 0, failureCount: 0,
audience: 'business', audience: 'business',
audienceLabel: 'Business', audienceLabel: 'Business',
detailLabel: null, detailLabel: 'Workspace 04a0f049',
compactDetailLabel: '04a0f049',
inlineLabel: 'Business · Workspace 04a0f049',
}, },
{ {
id: 'personal@example.com', id: 'personal@example.com',
@@ -87,11 +89,27 @@ const groupedAccount: AccountData = {
failureCount: 1, failureCount: 1,
audience: 'personal', audience: 'personal',
audienceLabel: 'Personal', audienceLabel: 'Personal',
detailLabel: null, detailLabel: 'Free',
compactDetailLabel: 'Free',
inlineLabel: 'Personal · Free',
}, },
], ],
}; };
const groupedAccountWithProPersonal: AccountData = {
...groupedAccount,
variants: groupedAccount.variants?.map((variant) =>
variant.audience === 'personal'
? {
...variant,
detailLabel: 'Pro',
compactDetailLabel: 'Pro',
inlineLabel: 'Personal · Pro',
}
: variant
),
};
describe('AccountCard grouped quota tooltip', () => { describe('AccountCard grouped quota tooltip', () => {
beforeEach(() => { beforeEach(() => {
mockedUseAccountQuota.mockReturnValue({ mockedUseAccountQuota.mockReturnValue({
@@ -105,13 +123,13 @@ describe('AccountCard grouped quota tooltip', () => {
isLoading: false, isLoading: false,
}, },
{ {
data: makeCodexQuota('plus', 64, 42), data: makeCodexQuota('free', 64, 42),
isLoading: false, isLoading: false,
}, },
] as ReturnType<typeof useAccountQuotas>); ] as ReturnType<typeof useAccountQuotas>);
}); });
it('shows provider quota tooltip content for each grouped personal/business row on hover', async () => { it('keeps grouped Codex account labels distinct and shows quota tooltips for each variant', async () => {
render( render(
<AccountCard <AccountCard
account={groupedAccount} account={groupedAccount}
@@ -130,7 +148,12 @@ describe('AccountCard grouped quota tooltip', () => {
/> />
); );
await userEvent.hover(screen.getByText('Business')); expect(
screen.getByTitle('Business · Workspace 04a0f049 • Personal · Free')
).toBeInTheDocument();
expect(screen.getByText('Biz')).toBeInTheDocument();
await userEvent.hover(screen.getByText('Business · Workspace 04a0f049'));
const businessPlan = (await screen.findAllByText('Plan: team')).find((node) => const businessPlan = (await screen.findAllByText('Plan: team')).find((node) =>
node.closest('[data-slot="tooltip-content"]') node.closest('[data-slot="tooltip-content"]')
); );
@@ -141,11 +164,35 @@ describe('AccountCard grouped quota tooltip', () => {
expect(tooltipContent?.className).toContain('text-popover-foreground'); expect(tooltipContent?.className).toContain('text-popover-foreground');
expect(tooltipContent?.className).toContain('max-w-[calc(100vw-2rem)]'); expect(tooltipContent?.className).toContain('max-w-[calc(100vw-2rem)]');
await userEvent.hover(screen.getByText('Personal')); await userEvent.hover(screen.getByText('Personal · Free'));
const personalPlan = (await screen.findAllByText('Plan: plus')).find((node) => const personalPlan = (await screen.findAllByText('Plan: free')).find((node) =>
node.closest('[data-slot="tooltip-content"]') node.closest('[data-slot="tooltip-content"]')
); );
expect(personalPlan).toBeInTheDocument(); expect(personalPlan).toBeInTheDocument();
expect(screen.getAllByText('Weekly usage limit').length).toBeGreaterThan(0); expect(screen.getAllByText('Weekly usage limit').length).toBeGreaterThan(0);
}); });
it('keeps richer grouped personal detail when quota planType is coarser runtime evidence', () => {
render(
<AccountCard
account={groupedAccountWithProPersonal}
zone="left"
originalIndex={0}
isHovered={false}
isDragging={false}
offset={{ x: 0, y: 0 }}
showDetails={false}
privacyMode={false}
onMouseEnter={() => undefined}
onMouseLeave={() => undefined}
onPointerDown={() => undefined}
onPointerMove={() => undefined}
onPointerUp={() => undefined}
/>
);
expect(screen.getByTitle('Business · Workspace 04a0f049 • Personal · Pro')).toBeInTheDocument();
expect(screen.getByText('Personal · Pro')).toBeInTheDocument();
expect(screen.queryByText('Personal · Free')).not.toBeInTheDocument();
});
}); });
@@ -1,7 +1,7 @@
import { render, screen } from '@tests/setup/test-utils'; import { render, screen } from '@tests/setup/test-utils';
import { describe, expect, it } from 'vitest'; import { describe, expect, it } from 'vitest';
import { AccountSurfaceCard } from '@/components/account/shared/account-surface-card'; import { AccountSurfaceCard } from '@/components/account/shared/account-surface-card';
import type { GeminiCliQuotaResult } from '@/lib/api-client'; import type { CodexQuotaResult, GeminiCliQuotaResult } from '@/lib/api-client';
function createGeminiQuotaResult( function createGeminiQuotaResult(
overrides: Partial<GeminiCliQuotaResult> = {} overrides: Partial<GeminiCliQuotaResult> = {}
@@ -29,6 +29,16 @@ function createGeminiQuotaResult(
}; };
} }
function createCodexQuotaResult(overrides: Partial<CodexQuotaResult> = {}): CodexQuotaResult {
return {
success: true,
windows: [],
planType: 'free',
lastUpdated: Date.now(),
...overrides,
};
}
describe('AccountSurfaceCard', () => { describe('AccountSurfaceCard', () => {
it('prefers live quota entitlement tier over a stale account tier for Gemini badges', () => { it('prefers live quota entitlement tier over a stale account tier for Gemini badges', () => {
render( render(
@@ -46,4 +56,40 @@ describe('AccountSurfaceCard', () => {
expect(screen.getByText('pro')).toBeInTheDocument(); expect(screen.getByText('pro')).toBeInTheDocument();
}); });
it('shows both personal identity and free-tier detail for compact Codex cards', () => {
render(
<AccountSurfaceCard
mode="compact"
provider="codex"
accountId="user@example.com#free"
email="user@example.com"
displayEmail="user@example.com"
tokenFile="codex-user@example.com-free.json"
showQuota={false}
/>
);
expect(screen.getByText('Pers')).toBeInTheDocument();
expect(screen.getByTitle('Personal')).toBeInTheDocument();
expect(screen.getByText('Free')).toBeInTheDocument();
});
it('keeps richer token-derived Codex personal detail when live quota planType is coarser', () => {
render(
<AccountSurfaceCard
mode="compact"
provider="codex"
accountId="user@example.com#pro"
email="user@example.com"
displayEmail="user@example.com"
tokenFile="codex-user@example.com-pro.json"
quota={createCodexQuotaResult({ planType: 'free' })}
showQuota={false}
/>
);
expect(screen.getByText('Pro')).toBeInTheDocument();
expect(screen.queryByText('Free')).not.toBeInTheDocument();
});
}); });
@@ -16,7 +16,7 @@ function makeAccount(overrides: Partial<OAuthAccount> & Pick<OAuthAccount, 'id'
} }
describe('buildAccountVisualGroups', () => { describe('buildAccountVisualGroups', () => {
it('orders grouped codex variants by audience consistently', () => { it('preserves grouped codex variant identity details while ordering by audience', () => {
const groups = buildAccountVisualGroups([ const groups = buildAccountVisualGroups([
makeAccount({ makeAccount({
id: 'kaidu.kd@gmail.com#free', id: 'kaidu.kd@gmail.com#free',
@@ -33,9 +33,36 @@ describe('buildAccountVisualGroups', () => {
'business', 'business',
'personal', 'personal',
]); ]);
expect(groups[0]?.variants?.map((variant) => variant.inlineLabel)).toEqual([
'Business · Workspace 04a0f049',
'Personal · Free',
]);
expect(groups[0]?.variants?.map((variant) => variant.compactDetailLabel)).toEqual([
'04a0f049',
'Free',
]);
expect(groups[0]?.memberIds).toEqual([ expect(groups[0]?.memberIds).toEqual([
'kaidu.kd@gmail.com#04a0f049-team', 'kaidu.kd@gmail.com#04a0f049-team',
'kaidu.kd@gmail.com#free', 'kaidu.kd@gmail.com#free',
]); ]);
}); });
it('keeps multiple personal codex plans distinct inside the same grouped card', () => {
const groups = buildAccountVisualGroups([
makeAccount({
id: 'kaidu.kd@gmail.com#plus',
tokenFile: 'codex-kaidu.kd@gmail.com-plus.json',
}),
makeAccount({
id: 'kaidu.kd@gmail.com#free',
tokenFile: 'codex-kaidu.kd@gmail.com-free.json',
}),
]);
expect(groups).toHaveLength(1);
expect(groups[0]?.variants?.map((variant) => variant.inlineLabel)).toEqual([
'Personal · Free',
'Personal · Plus',
]);
});
}); });