diff --git a/src/components/topbar/CurrentUserPopover.test.ts b/src/components/topbar/CurrentUserPopover.test.ts index 1ad2321da..48477b934 100644 --- a/src/components/topbar/CurrentUserPopover.test.ts +++ b/src/components/topbar/CurrentUserPopover.test.ts @@ -1,10 +1,10 @@ import type { VueWrapper } from '@vue/test-utils' import { mount } from '@vue/test-utils' -import Button from 'primevue/button' import { afterAll, beforeEach, describe, expect, it, vi } from 'vitest' import { h } from 'vue' import { createI18n } from 'vue-i18n' +import { formatCreditsFromCents } from '@/base/credits/comfyCredits' import enMessages from '@/locales/en/main.json' with { type: 'json' } import CurrentUserPopover from './CurrentUserPopover.vue' @@ -74,7 +74,9 @@ vi.mock('@/stores/firebaseAuthStore', () => ({ useFirebaseAuthStore: vi.fn(() => ({ getAuthHeader: vi .fn() - .mockResolvedValue({ Authorization: 'Bearer mock-token' }) + .mockResolvedValue({ Authorization: 'Bearer mock-token' }), + balance: { amount_micros: 100_000 }, // 100,000 cents = ~211,000 credits + isFetchingBalance: false })) })) @@ -107,6 +109,39 @@ vi.mock('@/components/common/UserCredit.vue', () => ({ } })) +// Mock formatCreditsFromCents +vi.mock('@/base/credits/comfyCredits', () => ({ + formatCreditsFromCents: vi.fn(({ cents }) => (cents / 100).toString()) +})) + +// Mock useExternalLink +vi.mock('@/composables/useExternalLink', () => ({ + useExternalLink: vi.fn(() => ({ + buildDocsUrl: vi.fn((path) => `https://docs.comfy.org${path}`) + })) +})) + +// Mock useFeatureFlags +vi.mock('@/composables/useFeatureFlags', () => ({ + useFeatureFlags: vi.fn(() => ({ + flags: { + subscriptionTiersEnabled: true + } + })) +})) + +// Mock useTelemetry +vi.mock('@/platform/telemetry', () => ({ + useTelemetry: vi.fn(() => ({ + trackAddApiCreditButtonClicked: vi.fn() + })) +})) + +// Mock isCloud +vi.mock('@/platform/distribution/types', () => ({ + isCloud: true +})) + vi.mock('@/platform/cloud/subscription/components/SubscribeButton.vue', () => ({ default: { name: 'SubscribeButtonMock', @@ -145,27 +180,37 @@ describe('CurrentUserPopover', () => { expect(wrapper.text()).toContain('test@example.com') }) - it('renders logout button with correct props', () => { + it('calls formatCreditsFromCents with correct parameters and displays formatted credits', () => { const wrapper = mountComponent() - // Find all buttons and get the logout button (last button) - const buttons = wrapper.findAllComponents(Button) - const logoutButton = buttons[4] + expect(formatCreditsFromCents).toHaveBeenCalledWith({ + cents: 100_000, + locale: 'en', + numberOptions: { + minimumFractionDigits: 0, + maximumFractionDigits: 2 + } + }) - // Check that logout button has correct props - expect(logoutButton.props('label')).toBe('Log Out') - expect(logoutButton.props('icon')).toBe('pi pi-sign-out') + // Verify the formatted credit string (1000) is rendered in the DOM + expect(wrapper.text()).toContain('1000') }) - it('opens user settings and emits close event when settings button is clicked', async () => { + it('renders logout menu item with correct text', () => { const wrapper = mountComponent() - // Find all buttons and get the settings button (third button) - const buttons = wrapper.findAllComponents(Button) - const settingsButton = buttons[2] + const logoutItem = wrapper.find('[data-testid="logout-menu-item"]') + expect(logoutItem.exists()).toBe(true) + expect(wrapper.text()).toContain('Log Out') + }) - // Click the settings button - await settingsButton.trigger('click') + it('opens user settings and emits close event when settings item is clicked', async () => { + const wrapper = mountComponent() + + const settingsItem = wrapper.find('[data-testid="user-settings-menu-item"]') + expect(settingsItem.exists()).toBe(true) + + await settingsItem.trigger('click') // Verify showSettingsDialog was called with 'user' expect(mockShowSettingsDialog).toHaveBeenCalledWith('user') @@ -175,15 +220,13 @@ describe('CurrentUserPopover', () => { expect(wrapper.emitted('close')!.length).toBe(1) }) - it('calls logout function and emits close event when logout button is clicked', async () => { + it('calls logout function and emits close event when logout item is clicked', async () => { const wrapper = mountComponent() - // Find all buttons and get the logout button (last button) - const buttons = wrapper.findAllComponents(Button) - const logoutButton = buttons[4] + const logoutItem = wrapper.find('[data-testid="logout-menu-item"]') + expect(logoutItem.exists()).toBe(true) - // Click the logout button - await logoutButton.trigger('click') + await logoutItem.trigger('click') // Verify handleSignOut was called expect(mockHandleSignOut).toHaveBeenCalled() @@ -193,15 +236,15 @@ describe('CurrentUserPopover', () => { expect(wrapper.emitted('close')!.length).toBe(1) }) - it('opens API pricing docs and emits close event when API pricing button is clicked', async () => { + it('opens API pricing docs and emits close event when partner nodes item is clicked', async () => { const wrapper = mountComponent() - // Find all buttons and get the Partner Nodes info button (first one) - const buttons = wrapper.findAllComponents(Button) - const partnerNodesButton = buttons[0] + const partnerNodesItem = wrapper.find( + '[data-testid="partner-nodes-menu-item"]' + ) + expect(partnerNodesItem.exists()).toBe(true) - // Click the Partner Nodes button - await partnerNodesButton.trigger('click') + await partnerNodesItem.trigger('click') // Verify window.open was called with the correct URL expect(window.open).toHaveBeenCalledWith( @@ -217,11 +260,9 @@ describe('CurrentUserPopover', () => { it('opens top-up dialog and emits close event when top-up button is clicked', async () => { const wrapper = mountComponent() - // Find all buttons and get the top-up button (second one) - const buttons = wrapper.findAllComponents(Button) - const topUpButton = buttons[1] + const topUpButton = wrapper.find('[data-testid="add-credits-button"]') + expect(topUpButton.exists()).toBe(true) - // Click the top-up button await topUpButton.trigger('click') // Verify showTopUpCreditsDialog was called diff --git a/src/components/topbar/CurrentUserPopover.vue b/src/components/topbar/CurrentUserPopover.vue index 1c964960f..144d3731f 100644 --- a/src/components/topbar/CurrentUserPopover.vue +++ b/src/components/topbar/CurrentUserPopover.vue @@ -1,120 +1,131 @@ - + - - - + + - - - {{ userDisplayName || $t('g.user') }} - - - {{ userEmail }} - - + + + {{ userDisplayName || $t('g.user') }} + + + {{ userEmail }} + - - - - - - {{ - $t('credits.unified.message') - }} - - - + + + + {{ + formattedBalance + }} + - + + + + {{ + $t('credits.unified.message') + }} + - + - + + {{ + $t('subscription.partnerNodesCredits') + }} + + + + > + + {{ + $t(planSettingsLabel) + }} + - + + + {{ + $t('userSettings.title') + }} + - + + + > + + {{ + $t('auth.signOut.signOut') + }} +
- {{ userEmail }} -
+ {{ userEmail }} +