mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-01-26 19:09:52 +00:00
[refactor] Replace manual semantic version utilities/functions with semver package (#5653)
## Summary - Replace custom `compareVersions()` with `semver.compare()` - Replace custom `isSemVer()` with `semver.valid()` - Remove deprecated version comparison functions from `formatUtil.ts` - Update all version comparison logic across components and stores - Fix tests to use semver mocking instead of formatUtil mocking ## Benefits - **Industry standard**: Uses well-maintained, battle-tested `semver` package - **Better reliability**: Handles edge cases more robustly than custom implementation - **Consistent behavior**: All version comparisons now use the same underlying logic - **Type safety**: Better TypeScript support with proper semver types Fixes #4787 ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-5653-refactor-Replace-manual-semantic-version-utilities-functions-with-semver-package-2736d73d365081fb8498ee11cbcc10e2) by [Unito](https://www.unito.io) --------- Co-authored-by: DrJKL <DrJKL@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -43,11 +43,11 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import Message from 'primevue/message'
|
||||
import { compare } from 'semver'
|
||||
import { computed } from 'vue'
|
||||
|
||||
import type { LGraphNode } from '@/lib/litegraph/src/litegraph'
|
||||
import { useSystemStatsStore } from '@/stores/systemStatsStore'
|
||||
import { compareVersions } from '@/utils/formatUtil'
|
||||
|
||||
const props = defineProps<{
|
||||
missingCoreNodes: Record<string, LGraphNode[]>
|
||||
@@ -68,7 +68,7 @@ const currentComfyUIVersion = computed<string | null>(() => {
|
||||
const sortedMissingCoreNodes = computed(() => {
|
||||
return Object.entries(props.missingCoreNodes).sort(([a], [b]) => {
|
||||
// Sort by version in descending order (newest first)
|
||||
return compareVersions(b, a) // Reversed for descending order
|
||||
return compare(b, a) // Reversed for descending order
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { compare, valid } from 'semver'
|
||||
import { computed } from 'vue'
|
||||
|
||||
import type { components } from '@/types/comfyRegistryTypes'
|
||||
import { compareVersions, isSemVer } from '@/utils/formatUtil'
|
||||
import { useComfyManagerStore } from '@/workbench/extensions/manager/stores/comfyManagerStore'
|
||||
|
||||
export const usePackUpdateStatus = (
|
||||
@@ -16,14 +16,14 @@ export const usePackUpdateStatus = (
|
||||
const latestVersion = computed(() => nodePack.latest_version?.version)
|
||||
|
||||
const isNightlyPack = computed(
|
||||
() => !!installedVersion.value && !isSemVer(installedVersion.value)
|
||||
() => !!installedVersion.value && !valid(installedVersion.value)
|
||||
)
|
||||
|
||||
const isUpdateAvailable = computed(() => {
|
||||
if (!isInstalled.value || isNightlyPack.value || !latestVersion.value) {
|
||||
return false
|
||||
}
|
||||
return compareVersions(latestVersion.value, installedVersion.value) > 0
|
||||
return compare(latestVersion.value, installedVersion.value) > 0
|
||||
})
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { compare, valid } from 'semver'
|
||||
import { computed, onMounted } from 'vue'
|
||||
|
||||
import { useInstalledPacks } from '@/composables/nodePack/useInstalledPacks'
|
||||
import type { components } from '@/types/comfyRegistryTypes'
|
||||
import { compareVersions, isSemVer } from '@/utils/formatUtil'
|
||||
import { useComfyManagerStore } from '@/workbench/extensions/manager/stores/comfyManagerStore'
|
||||
|
||||
/**
|
||||
@@ -25,13 +25,13 @@ export const useUpdateAvailableNodes = () => {
|
||||
)
|
||||
const latestVersion = pack.latest_version?.version
|
||||
|
||||
const isNightlyPack = !!installedVersion && !isSemVer(installedVersion)
|
||||
const isNightlyPack = !!installedVersion && !valid(installedVersion)
|
||||
|
||||
if (isNightlyPack || !latestVersion) {
|
||||
return false
|
||||
}
|
||||
|
||||
return compareVersions(latestVersion, installedVersion) > 0
|
||||
return compare(latestVersion, installedVersion) > 0
|
||||
}
|
||||
|
||||
// Same filtering logic as ManagerDialogContent.vue
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import _ from 'es-toolkit/compat'
|
||||
import { defineStore } from 'pinia'
|
||||
import { compare, valid } from 'semver'
|
||||
import { ref } from 'vue'
|
||||
|
||||
import type { SettingParams } from '@/platform/settings/types'
|
||||
@@ -7,7 +8,6 @@ import type { Settings } from '@/schemas/apiSchema'
|
||||
import { api } from '@/scripts/api'
|
||||
import { app } from '@/scripts/app'
|
||||
import type { TreeNode } from '@/types/treeExplorerTypes'
|
||||
import { compareVersions, isSemVer } from '@/utils/formatUtil'
|
||||
|
||||
export const getSettingInfo = (setting: SettingParams) => {
|
||||
const parts = setting.category || setting.id.split('.')
|
||||
@@ -132,20 +132,25 @@ export const useSettingStore = defineStore('setting', () => {
|
||||
|
||||
if (installedVersion) {
|
||||
const sortedVersions = Object.keys(defaultsByInstallVersion).sort(
|
||||
(a, b) => compareVersions(b, a)
|
||||
(a, b) => compare(b, a)
|
||||
)
|
||||
|
||||
for (const version of sortedVersions) {
|
||||
// Ensure the version is in a valid format before comparing
|
||||
if (!isSemVer(version)) {
|
||||
if (!valid(version)) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (compareVersions(installedVersion, version) >= 0) {
|
||||
const versionedDefault = defaultsByInstallVersion[version]
|
||||
return typeof versionedDefault === 'function'
|
||||
? versionedDefault()
|
||||
: versionedDefault
|
||||
if (compare(installedVersion, version) >= 0) {
|
||||
const versionedDefault =
|
||||
defaultsByInstallVersion[
|
||||
version as keyof typeof defaultsByInstallVersion
|
||||
]
|
||||
if (versionedDefault !== undefined) {
|
||||
return typeof versionedDefault === 'function'
|
||||
? versionedDefault()
|
||||
: versionedDefault
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { until } from '@vueuse/core'
|
||||
import { defineStore } from 'pinia'
|
||||
import { compare } from 'semver'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
import { useSettingStore } from '@/platform/settings/settingStore'
|
||||
import { useSystemStatsStore } from '@/stores/systemStatsStore'
|
||||
import { isElectron } from '@/utils/envUtil'
|
||||
import { compareVersions, stringToLocale } from '@/utils/formatUtil'
|
||||
import { stringToLocale } from '@/utils/formatUtil'
|
||||
|
||||
import { type ReleaseNote, useReleaseService } from './releaseService'
|
||||
|
||||
@@ -56,16 +57,19 @@ export const useReleaseStore = defineStore('release', () => {
|
||||
const isNewVersionAvailable = computed(
|
||||
() =>
|
||||
!!recentRelease.value &&
|
||||
compareVersions(
|
||||
compare(
|
||||
recentRelease.value.version,
|
||||
currentComfyUIVersion.value
|
||||
currentComfyUIVersion.value || '0.0.0'
|
||||
) > 0
|
||||
)
|
||||
|
||||
const isLatestVersion = computed(
|
||||
() =>
|
||||
!!recentRelease.value &&
|
||||
!compareVersions(recentRelease.value.version, currentComfyUIVersion.value)
|
||||
compare(
|
||||
recentRelease.value.version,
|
||||
currentComfyUIVersion.value || '0.0.0'
|
||||
) === 0
|
||||
)
|
||||
|
||||
const hasMediumOrHighAttention = computed(() =>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { until, useStorage } from '@vueuse/core'
|
||||
import { defineStore } from 'pinia'
|
||||
import * as semver from 'semver'
|
||||
import { gt, valid } from 'semver'
|
||||
import { computed } from 'vue'
|
||||
|
||||
import config from '@/config'
|
||||
@@ -26,13 +26,13 @@ export const useVersionCompatibilityStore = defineStore(
|
||||
if (
|
||||
!frontendVersion.value ||
|
||||
!requiredFrontendVersion.value ||
|
||||
!semver.valid(frontendVersion.value) ||
|
||||
!semver.valid(requiredFrontendVersion.value)
|
||||
!valid(frontendVersion.value) ||
|
||||
!valid(requiredFrontendVersion.value)
|
||||
) {
|
||||
return false
|
||||
}
|
||||
// Returns true if required version is greater than frontend version
|
||||
return semver.gt(requiredFrontendVersion.value, frontendVersion.value)
|
||||
return gt(requiredFrontendVersion.value, frontendVersion.value)
|
||||
})
|
||||
|
||||
const isFrontendNewer = computed(() => {
|
||||
|
||||
@@ -364,39 +364,6 @@ export const downloadUrlToHfRepoUrl = (url: string): string => {
|
||||
}
|
||||
}
|
||||
|
||||
export const isSemVer = (
|
||||
version: string
|
||||
): version is `${number}.${number}.${number}` => {
|
||||
const regex = /^\d+\.\d+\.\d+$/
|
||||
return regex.test(version)
|
||||
}
|
||||
|
||||
const normalizeVersion = (version: string) =>
|
||||
version
|
||||
.split(/[+.-]/)
|
||||
.map(Number)
|
||||
.filter((part) => !Number.isNaN(part))
|
||||
|
||||
export function compareVersions(
|
||||
versionA: string | undefined,
|
||||
versionB: string | undefined
|
||||
): number {
|
||||
versionA ??= '0.0.0'
|
||||
versionB ??= '0.0.0'
|
||||
|
||||
const aParts = normalizeVersion(versionA)
|
||||
const bParts = normalizeVersion(versionB)
|
||||
|
||||
for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) {
|
||||
const aPart = aParts[i] ?? 0
|
||||
const bPart = bParts[i] ?? 0
|
||||
if (aPart < bPart) return -1
|
||||
if (aPart > bPart) return 1
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts Metronome's integer amount back to a formatted currency string.
|
||||
* For USD, converts from cents to dollars.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import * as semver from 'semver'
|
||||
import { clean, satisfies } from 'semver'
|
||||
|
||||
import type {
|
||||
ConflictDetail,
|
||||
@@ -11,7 +11,7 @@ import type {
|
||||
* @returns Cleaned version string or original if cleaning fails
|
||||
*/
|
||||
export function cleanVersion(version: string): string {
|
||||
return semver.clean(version) || version
|
||||
return clean(version) || version
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -23,7 +23,7 @@ export function cleanVersion(version: string): string {
|
||||
export function satisfiesVersion(version: string, range: string): boolean {
|
||||
try {
|
||||
const cleanedVersion = cleanVersion(version)
|
||||
return semver.satisfies(cleanedVersion, range)
|
||||
return satisfies(cleanedVersion, range)
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -43,11 +43,11 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import Popover from 'primevue/popover'
|
||||
import { valid as validSemver } from 'semver'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
|
||||
import { usePackUpdateStatus } from '@/composables/nodePack/usePackUpdateStatus'
|
||||
import type { components } from '@/types/comfyRegistryTypes'
|
||||
import { isSemVer } from '@/utils/formatUtil'
|
||||
import PackVersionSelectorPopover from '@/workbench/extensions/manager/components/manager/PackVersionSelectorPopover.vue'
|
||||
import { useComfyManagerStore } from '@/workbench/extensions/manager/stores/comfyManagerStore'
|
||||
|
||||
@@ -81,7 +81,9 @@ const installedVersion = computed(() => {
|
||||
'nightly'
|
||||
|
||||
// If Git hash, truncate to 7 characters
|
||||
return isSemVer(version) ? version : version.slice(0, TRUNCATED_HASH_LENGTH)
|
||||
return validSemver(version)
|
||||
? version
|
||||
: version.slice(0, TRUNCATED_HASH_LENGTH)
|
||||
})
|
||||
|
||||
const toggleVersionSelector = (event: Event) => {
|
||||
|
||||
@@ -84,6 +84,7 @@ import { whenever } from '@vueuse/core'
|
||||
import Button from 'primevue/button'
|
||||
import Listbox from 'primevue/listbox'
|
||||
import ProgressSpinner from 'primevue/progressspinner'
|
||||
import { valid as validSemver } from 'semver'
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
@@ -94,7 +95,6 @@ import { useConflictDetection } from '@/composables/useConflictDetection'
|
||||
import { useComfyRegistryService } from '@/services/comfyRegistryService'
|
||||
import type { components } from '@/types/comfyRegistryTypes'
|
||||
import { getJoinedConflictMessages } from '@/utils/conflictMessageUtil'
|
||||
import { isSemVer } from '@/utils/formatUtil'
|
||||
import { useComfyManagerStore } from '@/workbench/extensions/manager/stores/comfyManagerStore'
|
||||
import type { components as ManagerComponents } from '@/workbench/extensions/manager/types/generatedManagerTypes'
|
||||
|
||||
@@ -142,7 +142,7 @@ onMounted(() => {
|
||||
getInitialSelectedVersion() ?? SelectedVersionValues.LATEST
|
||||
selectedVersion.value =
|
||||
// Use NIGHTLY when version is a Git hash
|
||||
isSemVer(initialVersion) ? initialVersion : SelectedVersionValues.NIGHTLY
|
||||
validSemver(initialVersion) ? initialVersion : SelectedVersionValues.NIGHTLY
|
||||
})
|
||||
|
||||
const getInitialSelectedVersion = () => {
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { compare, valid } from 'semver'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { nextTick, ref } from 'vue'
|
||||
|
||||
import { useInstalledPacks } from '@/composables/nodePack/useInstalledPacks'
|
||||
import { useUpdateAvailableNodes } from '@/composables/nodePack/useUpdateAvailableNodes'
|
||||
// Import mocked utils
|
||||
import { compareVersions, isSemVer } from '@/utils/formatUtil'
|
||||
import { useComfyManagerStore } from '@/workbench/extensions/manager/stores/comfyManagerStore'
|
||||
|
||||
// Mock Vue's onMounted to execute immediately for testing
|
||||
@@ -25,16 +24,16 @@ vi.mock('@/workbench/extensions/manager/stores/comfyManagerStore', () => ({
|
||||
useComfyManagerStore: vi.fn()
|
||||
}))
|
||||
|
||||
vi.mock('@/utils/formatUtil', () => ({
|
||||
compareVersions: vi.fn(),
|
||||
isSemVer: vi.fn()
|
||||
vi.mock('semver', () => ({
|
||||
compare: vi.fn(),
|
||||
valid: vi.fn()
|
||||
}))
|
||||
|
||||
const mockUseInstalledPacks = vi.mocked(useInstalledPacks)
|
||||
const mockUseComfyManagerStore = vi.mocked(useComfyManagerStore)
|
||||
|
||||
const mockCompareVersions = vi.mocked(compareVersions)
|
||||
const mockIsSemVer = vi.mocked(isSemVer)
|
||||
const mockSemverCompare = vi.mocked(compare)
|
||||
const mockSemverValid = vi.mocked(valid)
|
||||
|
||||
describe('useUpdateAvailableNodes', () => {
|
||||
const mockInstalledPacks = [
|
||||
@@ -86,19 +85,19 @@ describe('useUpdateAvailableNodes', () => {
|
||||
}
|
||||
})
|
||||
|
||||
mockIsSemVer.mockImplementation(
|
||||
(version: string): version is `${number}.${number}.${number}` => {
|
||||
return !version.includes('nightly')
|
||||
}
|
||||
)
|
||||
mockSemverValid.mockImplementation((version) => {
|
||||
return version &&
|
||||
typeof version === 'string' &&
|
||||
!version.includes('nightly')
|
||||
? version
|
||||
: null
|
||||
})
|
||||
|
||||
mockCompareVersions.mockImplementation(
|
||||
(latest: string | undefined, installed: string | undefined) => {
|
||||
if (latest === '2.0.0' && installed === '1.0.0') return 1 // outdated
|
||||
if (latest === '1.0.0' && installed === '1.0.0') return 0 // up to date
|
||||
return 0
|
||||
}
|
||||
)
|
||||
mockSemverCompare.mockImplementation((latest, installed) => {
|
||||
if (latest === '2.0.0' && installed === '1.0.0') return 1 // outdated
|
||||
if (latest === '1.0.0' && installed === '1.0.0') return 0 // up to date
|
||||
return 0
|
||||
})
|
||||
|
||||
mockUseComfyManagerStore.mockReturnValue({
|
||||
isPackInstalled: mockIsPackInstalled,
|
||||
@@ -322,10 +321,10 @@ describe('useUpdateAvailableNodes', () => {
|
||||
// Access the computed to trigger the logic
|
||||
expect(updateAvailableNodePacks.value).toBeDefined()
|
||||
|
||||
expect(mockCompareVersions).toHaveBeenCalledWith('2.0.0', '1.0.0')
|
||||
expect(mockSemverCompare).toHaveBeenCalledWith('2.0.0', '1.0.0')
|
||||
})
|
||||
|
||||
it('calls isSemVer to check nightly versions', () => {
|
||||
it('calls semver.valid to check nightly versions', () => {
|
||||
mockUseInstalledPacks.mockReturnValue({
|
||||
installedPacks: ref([mockInstalledPacks[2]]), // pack-3: nightly
|
||||
isLoading: ref(false),
|
||||
@@ -338,7 +337,7 @@ describe('useUpdateAvailableNodes', () => {
|
||||
// Access the computed to trigger the logic
|
||||
expect(updateAvailableNodePacks.value).toBeDefined()
|
||||
|
||||
expect(mockIsSemVer).toHaveBeenCalledWith('nightly-abc123')
|
||||
expect(mockSemverValid).toHaveBeenCalledWith('nightly-abc123')
|
||||
})
|
||||
|
||||
it('calls isPackInstalled for each pack', () => {
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { compare as semverCompare } from 'semver'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import { useReleaseStore } from '@/platform/updates/common/releaseStore'
|
||||
|
||||
// Mock the dependencies
|
||||
vi.mock('@/utils/formatUtil')
|
||||
vi.mock('semver')
|
||||
vi.mock('@/utils/envUtil')
|
||||
vi.mock('@/platform/updates/common/releaseService')
|
||||
vi.mock('@/platform/settings/settingStore')
|
||||
@@ -113,17 +114,15 @@ describe('useReleaseStore', () => {
|
||||
expect(store.recentReleases).toEqual(releases.slice(0, 3))
|
||||
})
|
||||
|
||||
it('should show update button (shouldShowUpdateButton)', async () => {
|
||||
const { compareVersions } = await import('@/utils/formatUtil')
|
||||
vi.mocked(compareVersions).mockReturnValue(1) // newer version available
|
||||
it('should show update button (shouldShowUpdateButton)', () => {
|
||||
vi.mocked(semverCompare).mockReturnValue(1) // newer version available
|
||||
|
||||
store.releases = [mockRelease]
|
||||
expect(store.shouldShowUpdateButton).toBe(true)
|
||||
})
|
||||
|
||||
it('should not show update button when no new version', async () => {
|
||||
const { compareVersions } = await import('@/utils/formatUtil')
|
||||
vi.mocked(compareVersions).mockReturnValue(-1) // current version is newer
|
||||
it('should not show update button when no new version', () => {
|
||||
vi.mocked(semverCompare).mockReturnValue(-1) // current version is newer
|
||||
|
||||
store.releases = [mockRelease]
|
||||
expect(store.shouldShowUpdateButton).toBe(false)
|
||||
@@ -131,21 +130,20 @@ describe('useReleaseStore', () => {
|
||||
})
|
||||
|
||||
describe('showVersionUpdates setting', () => {
|
||||
beforeEach(() => {
|
||||
beforeEach(async () => {
|
||||
store.releases = [mockRelease]
|
||||
})
|
||||
|
||||
describe('when notifications are enabled', () => {
|
||||
beforeEach(() => {
|
||||
beforeEach(async () => {
|
||||
mockSettingStore.get.mockImplementation((key: string) => {
|
||||
if (key === 'Comfy.Notification.ShowVersionUpdates') return true
|
||||
return null
|
||||
})
|
||||
})
|
||||
|
||||
it('should show toast for medium/high attention releases', async () => {
|
||||
const { compareVersions } = await import('@/utils/formatUtil')
|
||||
vi.mocked(compareVersions).mockReturnValue(1)
|
||||
it('should show toast for medium/high attention releases', () => {
|
||||
vi.mocked(semverCompare).mockReturnValue(1)
|
||||
|
||||
// Need multiple releases for hasMediumOrHighAttention to work
|
||||
const mediumRelease = {
|
||||
@@ -158,17 +156,16 @@ describe('useReleaseStore', () => {
|
||||
expect(store.shouldShowToast).toBe(true)
|
||||
})
|
||||
|
||||
it('should show red dot for new versions', async () => {
|
||||
const { compareVersions } = await import('@/utils/formatUtil')
|
||||
vi.mocked(compareVersions).mockReturnValue(1)
|
||||
it('should show red dot for new versions', () => {
|
||||
vi.mocked(semverCompare).mockReturnValue(1)
|
||||
|
||||
expect(store.shouldShowRedDot).toBe(true)
|
||||
})
|
||||
|
||||
it('should show popup for latest version', async () => {
|
||||
it('should show popup for latest version', () => {
|
||||
mockSystemStatsStore.systemStats.system.comfyui_version = '1.2.0'
|
||||
const { compareVersions } = await import('@/utils/formatUtil')
|
||||
vi.mocked(compareVersions).mockReturnValue(0)
|
||||
|
||||
vi.mocked(semverCompare).mockReturnValue(0)
|
||||
|
||||
expect(store.shouldShowPopup).toBe(true)
|
||||
})
|
||||
@@ -181,37 +178,36 @@ describe('useReleaseStore', () => {
|
||||
expect(mockReleaseService.getReleases).toHaveBeenCalledWith({
|
||||
project: 'comfyui',
|
||||
current_version: '1.0.0',
|
||||
form_factor: 'git-windows'
|
||||
form_factor: 'git-windows',
|
||||
locale: 'en'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('when notifications are disabled', () => {
|
||||
beforeEach(() => {
|
||||
beforeEach(async () => {
|
||||
mockSettingStore.get.mockImplementation((key: string) => {
|
||||
if (key === 'Comfy.Notification.ShowVersionUpdates') return false
|
||||
return null
|
||||
})
|
||||
})
|
||||
|
||||
it('should not show toast even with new version available', async () => {
|
||||
const { compareVersions } = await import('@/utils/formatUtil')
|
||||
vi.mocked(compareVersions).mockReturnValue(1)
|
||||
it('should not show toast even with new version available', () => {
|
||||
vi.mocked(semverCompare).mockReturnValue(1)
|
||||
|
||||
expect(store.shouldShowToast).toBe(false)
|
||||
})
|
||||
|
||||
it('should not show red dot even with new version available', async () => {
|
||||
const { compareVersions } = await import('@/utils/formatUtil')
|
||||
vi.mocked(compareVersions).mockReturnValue(1)
|
||||
it('should not show red dot even with new version available', () => {
|
||||
vi.mocked(semverCompare).mockReturnValue(1)
|
||||
|
||||
expect(store.shouldShowRedDot).toBe(false)
|
||||
})
|
||||
|
||||
it('should not show popup even for latest version', async () => {
|
||||
it('should not show popup even for latest version', () => {
|
||||
mockSystemStatsStore.systemStats.system.comfyui_version = '1.2.0'
|
||||
const { compareVersions } = await import('@/utils/formatUtil')
|
||||
vi.mocked(compareVersions).mockReturnValue(0)
|
||||
|
||||
vi.mocked(semverCompare).mockReturnValue(0)
|
||||
|
||||
expect(store.shouldShowPopup).toBe(false)
|
||||
})
|
||||
@@ -240,7 +236,8 @@ describe('useReleaseStore', () => {
|
||||
expect(mockReleaseService.getReleases).toHaveBeenCalledWith({
|
||||
project: 'comfyui',
|
||||
current_version: '1.0.0',
|
||||
form_factor: 'git-windows'
|
||||
form_factor: 'git-windows',
|
||||
locale: 'en'
|
||||
})
|
||||
expect(store.releases).toEqual([mockRelease])
|
||||
})
|
||||
@@ -254,7 +251,8 @@ describe('useReleaseStore', () => {
|
||||
expect(mockReleaseService.getReleases).toHaveBeenCalledWith({
|
||||
project: 'comfyui',
|
||||
current_version: '1.0.0',
|
||||
form_factor: 'desktop-mac'
|
||||
form_factor: 'desktop-mac',
|
||||
locale: 'en'
|
||||
})
|
||||
})
|
||||
|
||||
@@ -424,7 +422,7 @@ describe('useReleaseStore', () => {
|
||||
})
|
||||
|
||||
describe('action handlers', () => {
|
||||
beforeEach(() => {
|
||||
beforeEach(async () => {
|
||||
store.releases = [mockRelease]
|
||||
})
|
||||
|
||||
@@ -481,7 +479,7 @@ describe('useReleaseStore', () => {
|
||||
})
|
||||
|
||||
describe('popup visibility', () => {
|
||||
it('should show toast for medium/high attention releases', async () => {
|
||||
it('should show toast for medium/high attention releases', () => {
|
||||
mockSettingStore.get.mockImplementation((key: string) => {
|
||||
if (key === 'Comfy.Release.Version') return null
|
||||
if (key === 'Comfy.Release.Status') return null
|
||||
@@ -489,8 +487,7 @@ describe('useReleaseStore', () => {
|
||||
return null
|
||||
})
|
||||
|
||||
const { compareVersions } = await import('@/utils/formatUtil')
|
||||
vi.mocked(compareVersions).mockReturnValue(1)
|
||||
vi.mocked(semverCompare).mockReturnValue(1)
|
||||
|
||||
const mediumRelease = { ...mockRelease, attention: 'medium' as const }
|
||||
store.releases = [
|
||||
@@ -502,9 +499,8 @@ describe('useReleaseStore', () => {
|
||||
expect(store.shouldShowToast).toBe(true)
|
||||
})
|
||||
|
||||
it('should show red dot for new versions', async () => {
|
||||
const { compareVersions } = await import('@/utils/formatUtil')
|
||||
vi.mocked(compareVersions).mockReturnValue(1)
|
||||
it('should show red dot for new versions', () => {
|
||||
vi.mocked(semverCompare).mockReturnValue(1)
|
||||
mockSettingStore.get.mockImplementation((key: string) => {
|
||||
if (key === 'Comfy.Notification.ShowVersionUpdates') return true
|
||||
return null
|
||||
@@ -515,15 +511,14 @@ describe('useReleaseStore', () => {
|
||||
expect(store.shouldShowRedDot).toBe(true)
|
||||
})
|
||||
|
||||
it('should show popup for latest version', async () => {
|
||||
it('should show popup for latest version', () => {
|
||||
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
|
||||
})
|
||||
|
||||
const { compareVersions } = await import('@/utils/formatUtil')
|
||||
vi.mocked(compareVersions).mockReturnValue(0) // versions are equal (latest version)
|
||||
vi.mocked(semverCompare).mockReturnValue(0) // versions are equal (latest version)
|
||||
|
||||
store.releases = [mockRelease]
|
||||
|
||||
@@ -565,7 +560,7 @@ describe('useReleaseStore', () => {
|
||||
})
|
||||
|
||||
describe('isElectron environment checks', () => {
|
||||
beforeEach(() => {
|
||||
beforeEach(async () => {
|
||||
// Set up a new version available
|
||||
store.releases = [mockRelease]
|
||||
mockSettingStore.get.mockImplementation((key: string) => {
|
||||
@@ -580,9 +575,8 @@ describe('useReleaseStore', () => {
|
||||
vi.mocked(isElectron).mockReturnValue(true)
|
||||
})
|
||||
|
||||
it('should show toast when conditions are met', async () => {
|
||||
const { compareVersions } = await import('@/utils/formatUtil')
|
||||
vi.mocked(compareVersions).mockReturnValue(1)
|
||||
it('should show toast when conditions are met', () => {
|
||||
vi.mocked(semverCompare).mockReturnValue(1)
|
||||
|
||||
// Need multiple releases for hasMediumOrHighAttention
|
||||
const mediumRelease = {
|
||||
@@ -595,17 +589,16 @@ describe('useReleaseStore', () => {
|
||||
expect(store.shouldShowToast).toBe(true)
|
||||
})
|
||||
|
||||
it('should show red dot when new version available', async () => {
|
||||
const { compareVersions } = await import('@/utils/formatUtil')
|
||||
vi.mocked(compareVersions).mockReturnValue(1)
|
||||
it('should show red dot when new version available', () => {
|
||||
vi.mocked(semverCompare).mockReturnValue(1)
|
||||
|
||||
expect(store.shouldShowRedDot).toBe(true)
|
||||
})
|
||||
|
||||
it('should show popup for latest version', async () => {
|
||||
it('should show popup for latest version', () => {
|
||||
mockSystemStatsStore.systemStats.system.comfyui_version = '1.2.0'
|
||||
const { compareVersions } = await import('@/utils/formatUtil')
|
||||
vi.mocked(compareVersions).mockReturnValue(0)
|
||||
|
||||
vi.mocked(semverCompare).mockReturnValue(0)
|
||||
|
||||
expect(store.shouldShowPopup).toBe(true)
|
||||
})
|
||||
@@ -617,9 +610,8 @@ describe('useReleaseStore', () => {
|
||||
vi.mocked(isElectron).mockReturnValue(false)
|
||||
})
|
||||
|
||||
it('should NOT show toast even when all other conditions are met', async () => {
|
||||
const { compareVersions } = await import('@/utils/formatUtil')
|
||||
vi.mocked(compareVersions).mockReturnValue(1)
|
||||
it('should NOT show toast even when all other conditions are met', () => {
|
||||
vi.mocked(semverCompare).mockReturnValue(1)
|
||||
|
||||
// Set up all conditions that would normally show toast
|
||||
const mediumRelease = {
|
||||
@@ -632,16 +624,14 @@ describe('useReleaseStore', () => {
|
||||
expect(store.shouldShowToast).toBe(false)
|
||||
})
|
||||
|
||||
it('should NOT show red dot even when new version available', async () => {
|
||||
const { compareVersions } = await import('@/utils/formatUtil')
|
||||
vi.mocked(compareVersions).mockReturnValue(1)
|
||||
it('should NOT show red dot even when new version available', () => {
|
||||
vi.mocked(semverCompare).mockReturnValue(1)
|
||||
|
||||
expect(store.shouldShowRedDot).toBe(false)
|
||||
})
|
||||
|
||||
it('should NOT show toast regardless of attention level', async () => {
|
||||
const { compareVersions } = await import('@/utils/formatUtil')
|
||||
vi.mocked(compareVersions).mockReturnValue(1)
|
||||
it('should NOT show toast regardless of attention level', () => {
|
||||
vi.mocked(semverCompare).mockReturnValue(1)
|
||||
|
||||
// Test with high attention releases
|
||||
const highRelease = {
|
||||
@@ -659,19 +649,18 @@ describe('useReleaseStore', () => {
|
||||
expect(store.shouldShowToast).toBe(false)
|
||||
})
|
||||
|
||||
it('should NOT show red dot even with high attention release', async () => {
|
||||
const { compareVersions } = await import('@/utils/formatUtil')
|
||||
vi.mocked(compareVersions).mockReturnValue(1)
|
||||
it('should NOT show red dot even with high attention release', () => {
|
||||
vi.mocked(semverCompare).mockReturnValue(1)
|
||||
|
||||
store.releases = [{ ...mockRelease, attention: 'high' as const }]
|
||||
|
||||
expect(store.shouldShowRedDot).toBe(false)
|
||||
})
|
||||
|
||||
it('should NOT show popup even for latest version', async () => {
|
||||
it('should NOT show popup even for latest version', () => {
|
||||
mockSystemStatsStore.systemStats.system.comfyui_version = '1.2.0'
|
||||
const { compareVersions } = await import('@/utils/formatUtil')
|
||||
vi.mocked(compareVersions).mockReturnValue(0)
|
||||
|
||||
vi.mocked(semverCompare).mockReturnValue(0)
|
||||
|
||||
expect(store.shouldShowPopup).toBe(false)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user