Skip to content
Merged
103 changes: 72 additions & 31 deletions src/components/topbar/CurrentUserPopover.test.ts
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -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
}))
}))

Expand Down Expand Up @@ -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',
Expand Down Expand Up @@ -145,27 +180,37 @@ describe('CurrentUserPopover', () => {
expect(wrapper.text()).toContain('[email protected]')
})

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"]')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'd be nice if we could find by a label or name.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In theory a label or name would cause more drift and bad signal

expect(logoutItem.exists()).toBe(true)
expect(wrapper.text()).toContain('Log Out')
})

it('opens user settings and emits close event when settings item is clicked', async () => {
const wrapper = mountComponent()

// Click the settings button
await settingsButton.trigger('click')
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')
Expand All @@ -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()
Expand All @@ -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(
Expand All @@ -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
Expand Down
Loading