Skip to content
2 changes: 1 addition & 1 deletion src/platform/updates/common/releaseService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ describe('useReleaseService', () => {
})

it('should set loading state correctly', async () => {
let resolvePromise: (value: any) => void
let resolvePromise: (value: unknown) => void
const promise = new Promise((resolve) => {
resolvePromise = resolve
})
Expand Down
81 changes: 56 additions & 25 deletions src/platform/updates/common/releaseStore.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { createPinia, setActivePinia } from 'pinia'
import { compare, valid } from 'semver'
import type { Mock } from 'vitest'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { ref } from 'vue'

import type { ReleaseNote } from '@/platform/updates/common/releaseService'
import { useReleaseStore } from '@/platform/updates/common/releaseStore'

// Mock the dependencies
Expand All @@ -19,9 +22,25 @@ vi.mock('@vueuse/core', () => ({

describe('useReleaseStore', () => {
let store: ReturnType<typeof useReleaseStore>
let mockReleaseService: any
let mockSettingStore: any
let mockSystemStatsStore: any
let mockReleaseService: {
getReleases: Mock
isLoading: ReturnType<typeof ref<boolean>>
error: ReturnType<typeof ref<string | null>>
}
let mockSettingStore: { get: Mock; set: Mock }
let mockSystemStatsStore: {
systemStats: {
system: {
comfyui_version: string
argv?: string[]
[key: string]: unknown
}
devices?: unknown[]
} | null
isInitialized: boolean
refetchSystemStats: Mock
getFormFactor: Mock
}

const mockRelease = {
id: 1,
Expand All @@ -38,11 +57,11 @@ describe('useReleaseStore', () => {
// Reset all mocks
vi.clearAllMocks()

// Setup mock services
// Setup mock services with proper refs
mockReleaseService = {
getReleases: vi.fn(),
isLoading: { value: false },
error: { value: null }
isLoading: ref(false),
error: ref(null)
}

mockSettingStore = {
Expand All @@ -68,9 +87,21 @@ describe('useReleaseStore', () => {
const { useSystemStatsStore } = await import('@/stores/systemStatsStore')
const { isElectron } = await import('@/utils/envUtil')

vi.mocked(useReleaseService).mockReturnValue(mockReleaseService)
vi.mocked(useSettingStore).mockReturnValue(mockSettingStore)
vi.mocked(useSystemStatsStore).mockReturnValue(mockSystemStatsStore)
vi.mocked(useReleaseService).mockReturnValue(
mockReleaseService as Partial<
ReturnType<typeof useReleaseService>
> as ReturnType<typeof useReleaseService>
)
vi.mocked(useSettingStore).mockReturnValue(
mockSettingStore as Partial<
ReturnType<typeof useSettingStore>
> as ReturnType<typeof useSettingStore>
)
vi.mocked(useSystemStatsStore).mockReturnValue(
mockSystemStatsStore as Partial<
ReturnType<typeof useSystemStatsStore>
> as ReturnType<typeof useSystemStatsStore>
)
vi.mocked(isElectron).mockReturnValue(true)
vi.mocked(valid).mockReturnValue('1.0.0')

Expand Down Expand Up @@ -171,7 +202,7 @@ describe('useReleaseStore', () => {
})

it('should show popup for latest version', () => {
mockSystemStatsStore.systemStats.system.comfyui_version = '1.2.0'
mockSystemStatsStore.systemStats!.system.comfyui_version = '1.2.0'

vi.mocked(compare).mockReturnValue(0)

Expand Down Expand Up @@ -213,7 +244,7 @@ describe('useReleaseStore', () => {
})

it('should not show popup even for latest version', () => {
mockSystemStatsStore.systemStats.system.comfyui_version = '1.2.0'
mockSystemStatsStore.systemStats!.system.comfyui_version = '1.2.0'

vi.mocked(compare).mockReturnValue(0)

Expand Down Expand Up @@ -265,7 +296,7 @@ describe('useReleaseStore', () => {
})

it('should skip fetching when --disable-api-nodes is present', async () => {
mockSystemStatsStore.systemStats.system.argv = ['--disable-api-nodes']
mockSystemStatsStore.systemStats!.system.argv = ['--disable-api-nodes']

await store.initialize()

Expand All @@ -274,7 +305,7 @@ describe('useReleaseStore', () => {
})

it('should skip fetching when --disable-api-nodes is one of multiple args', async () => {
mockSystemStatsStore.systemStats.system.argv = [
mockSystemStatsStore.systemStats!.system.argv = [
'--port',
'8080',
'--disable-api-nodes',
Expand All @@ -288,7 +319,7 @@ describe('useReleaseStore', () => {
})

it('should fetch normally when --disable-api-nodes is not present', async () => {
mockSystemStatsStore.systemStats.system.argv = [
mockSystemStatsStore.systemStats!.system.argv = [
'--port',
'8080',
'--verbose'
Expand All @@ -302,7 +333,7 @@ describe('useReleaseStore', () => {
})

it('should fetch normally when argv is undefined', async () => {
mockSystemStatsStore.systemStats.system.argv = undefined
mockSystemStatsStore.systemStats!.system.argv = undefined
mockReleaseService.getReleases.mockResolvedValue([mockRelease])

await store.initialize()
Expand Down Expand Up @@ -330,8 +361,8 @@ describe('useReleaseStore', () => {
})

it('should set loading state correctly', async () => {
let resolvePromise: (value: any) => void
const promise = new Promise((resolve) => {
let resolvePromise: (value: ReleaseNote[] | null) => void
const promise = new Promise<ReleaseNote[] | null>((resolve) => {
resolvePromise = resolve
})

Expand Down Expand Up @@ -372,7 +403,7 @@ describe('useReleaseStore', () => {

describe('--disable-api-nodes argument handling', () => {
it('should skip fetchReleases when --disable-api-nodes is present', async () => {
mockSystemStatsStore.systemStats.system.argv = ['--disable-api-nodes']
mockSystemStatsStore.systemStats!.system.argv = ['--disable-api-nodes']

await store.fetchReleases()

Expand All @@ -381,7 +412,7 @@ describe('useReleaseStore', () => {
})

it('should skip fetchReleases when --disable-api-nodes is among other args', async () => {
mockSystemStatsStore.systemStats.system.argv = [
mockSystemStatsStore.systemStats!.system.argv = [
'--port',
'8080',
'--disable-api-nodes',
Expand All @@ -395,7 +426,7 @@ describe('useReleaseStore', () => {
})

it('should proceed with fetchReleases when --disable-api-nodes is not present', async () => {
mockSystemStatsStore.systemStats.system.argv = [
mockSystemStatsStore.systemStats!.system.argv = [
'--port',
'8080',
'--verbose'
Expand All @@ -407,8 +438,8 @@ describe('useReleaseStore', () => {
expect(mockReleaseService.getReleases).toHaveBeenCalled()
})

it('should proceed with fetchReleases when argv is null', async () => {
mockSystemStatsStore.systemStats.system.argv = null
it('should proceed with fetchReleases when argv is undefined', async () => {
mockSystemStatsStore.systemStats!.system.argv = undefined
mockReleaseService.getReleases.mockResolvedValue([mockRelease])

await store.fetchReleases()
Expand Down Expand Up @@ -515,7 +546,7 @@ describe('useReleaseStore', () => {
})

it('should show popup for latest version', () => {
mockSystemStatsStore.systemStats.system.comfyui_version = '1.2.0' // Same as release
mockSystemStatsStore.systemStats!.system.comfyui_version = '1.2.0' // Same as release
mockSettingStore.get.mockImplementation((key: string) => {
if (key === 'Comfy.Notification.ShowVersionUpdates') return true
return null
Expand Down Expand Up @@ -592,7 +623,7 @@ describe('useReleaseStore', () => {
})

it('should show popup for latest version', () => {
mockSystemStatsStore.systemStats.system.comfyui_version = '1.2.0'
mockSystemStatsStore.systemStats!.system.comfyui_version = '1.2.0'

vi.mocked(compare).mockReturnValue(0)

Expand Down Expand Up @@ -649,7 +680,7 @@ describe('useReleaseStore', () => {
})

it('should NOT show popup even for latest version', () => {
mockSystemStatsStore.systemStats.system.comfyui_version = '1.2.0'
mockSystemStatsStore.systemStats!.system.comfyui_version = '1.2.0'

vi.mocked(compare).mockReturnValue(0)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,20 @@ vi.mock('@/scripts/api', () => ({
// Mock vue-i18n
vi.mock('vue-i18n', () => ({
useI18n: () => ({
t: (key: string, params?: any) => {
t: (key: string, params?: Record<string, string | number> | unknown) => {
if (key === 'g.versionMismatchWarning')
return 'Version Compatibility Warning'
if (key === 'g.versionMismatchWarningMessage' && params) {
return `${params.warning}: ${params.detail} Visit https://docs.comfy.org/installation/update_comfyui#common-update-issues for update instructions.`
const p = params as Record<string, string>
return `${p.warning}: ${p.detail} Visit https://docs.comfy.org/installation/update_comfyui#common-update-issues for update instructions.`
}
if (key === 'g.frontendOutdated' && params) {
return `Frontend version ${params.frontendVersion} is outdated. Backend requires ${params.requiredVersion} or higher.`
const p = params as Record<string, string>
return `Frontend version ${p.frontendVersion} is outdated. Backend requires ${p.requiredVersion} or higher.`
}
if (key === 'g.frontendNewer' && params) {
return `Frontend version ${params.frontendVersion} may not be compatible with backend version ${params.backendVersion}.`
const p = params as Record<string, string>
return `Frontend version ${p.frontendVersion} may not be compatible with backend version ${p.backendVersion}.`
}
return key
}
Expand Down
37 changes: 22 additions & 15 deletions src/platform/updates/common/versionCompatibilityStore.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,21 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { ref } from 'vue'

import { useVersionCompatibilityStore } from '@/platform/updates/common/versionCompatibilityStore'
import { useSettingStore } from '@/platform/settings/settingStore'
import { useSystemStatsStore } from '@/stores/systemStatsStore'

vi.mock('@/config', () => ({
default: {
app_version: '1.24.0'
}
}))

vi.mock('@/stores/systemStatsStore')
const mockUseSystemStatsStore = vi.hoisted(() => vi.fn())
vi.mock('@/stores/systemStatsStore', () => ({
useSystemStatsStore: mockUseSystemStatsStore
}))

// Mock settingStore
const mockUseSettingStore = vi.hoisted(() => vi.fn())
vi.mock('@/platform/settings/settingStore', () => ({
useSettingStore: vi.fn(() => ({
get: vi.fn(() => false) // Default to warnings enabled (false = not disabled)
}))
useSettingStore: mockUseSettingStore
}))

// Mock useStorage and until from VueUse
Expand All @@ -28,10 +27,16 @@ vi.mock('@vueuse/core', () => ({
until: vi.fn(() => Promise.resolve())
}))

type MockSystemStatsStore = {
systemStats: unknown
isInitialized: boolean
refetchSystemStats: ReturnType<typeof vi.fn>
}

describe('useVersionCompatibilityStore', () => {
let store: ReturnType<typeof useVersionCompatibilityStore>
let mockSystemStatsStore: any
let mockSettingStore: any
let mockSystemStatsStore: MockSystemStatsStore
let mockSettingStore: { get: ReturnType<typeof vi.fn> }

beforeEach(() => {
setActivePinia(createPinia())
Expand All @@ -49,8 +54,8 @@ describe('useVersionCompatibilityStore', () => {
get: vi.fn(() => false) // Default to warnings enabled
}

vi.mocked(useSystemStatsStore).mockReturnValue(mockSystemStatsStore)
vi.mocked(useSettingStore).mockReturnValue(mockSettingStore)
mockUseSystemStatsStore.mockReturnValue(mockSystemStatsStore)
mockUseSettingStore.mockReturnValue(mockSettingStore)

store = useVersionCompatibilityStore()
})
Expand Down Expand Up @@ -213,7 +218,9 @@ describe('useVersionCompatibilityStore', () => {

it('should not show warning when disabled via setting', async () => {
// Enable the disable setting
mockSettingStore.get.mockReturnValue(true)
;(
mockSettingStore as { get: ReturnType<typeof vi.fn> }
).get.mockReturnValue(true)

// Set up version mismatch that would normally show warning
mockSystemStatsStore.systemStats = {
Expand All @@ -227,9 +234,9 @@ describe('useVersionCompatibilityStore', () => {
await store.checkVersionCompatibility()

expect(store.shouldShowWarning).toBe(false)
expect(mockSettingStore.get).toHaveBeenCalledWith(
'Comfy.VersionCompatibility.DisableWarnings'
)
expect(
(mockSettingStore as { get: ReturnType<typeof vi.fn> }).get
).toHaveBeenCalledWith('Comfy.VersionCompatibility.DisableWarnings')
})
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'
import type { ReleaseNote } from '../common/releaseService'
import ReleaseNotificationToast from './ReleaseNotificationToast.vue'

interface TestWindow extends Window {
electronAPI?: Record<string, unknown>
}

const { commandExecuteMock } = vi.hoisted(() => ({
commandExecuteMock: vi.fn()
}))
Expand Down Expand Up @@ -192,7 +196,7 @@ describe('ReleaseNotificationToast', () => {
value: mockWindowOpen,
writable: true
})
;(window as any).electronAPI = {}
;(window as TestWindow).electronAPI = {}

wrapper = mountComponent()
await wrapper.vm.handleUpdate()
Expand All @@ -203,7 +207,7 @@ describe('ReleaseNotificationToast', () => {
expect(mockWindowOpen).not.toHaveBeenCalled()
expect(toastErrorHandlerMock).not.toHaveBeenCalled()

delete (window as any).electronAPI
delete (window as TestWindow).electronAPI
})

it('shows an error toast if the desktop updater flow fails in Electron', async () => {
Expand All @@ -220,15 +224,15 @@ describe('ReleaseNotificationToast', () => {
value: mockWindowOpen,
writable: true
})
;(window as any).electronAPI = {}
;(window as TestWindow).electronAPI = {}

wrapper = mountComponent()
await wrapper.vm.handleUpdate()

expect(toastErrorHandlerMock).toHaveBeenCalledWith(error)
expect(mockWindowOpen).not.toHaveBeenCalled()

delete (window as any).electronAPI
delete (window as TestWindow).electronAPI
})

it('calls handleShowChangelog when learn more link is clicked', async () => {
Expand Down
4 changes: 3 additions & 1 deletion src/platform/updates/components/WhatsNewPopup.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,9 @@ describe('WhatsNewPopup', () => {
wrapper = mountComponent()

// Call the close method directly instead of triggering DOM event
await (wrapper.vm as any).closePopup()
await (
wrapper.vm as typeof wrapper.vm & { closePopup: () => Promise<void> }
).closePopup()

expect(wrapper.emitted('whats-new-dismissed')).toBeTruthy()
})
Expand Down
Loading