mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-11 00:10:40 +00:00
feat: Add more Storybook stories for UI components
This commit is contained in:
@@ -2,10 +2,10 @@ import { createPinia, setActivePinia } from 'pinia'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import { useSelectedLiteGraphItems } from '@/composables/canvas/useSelectedLiteGraphItems'
|
||||
import type { LGraphNode } from '@/lib/litegraph/src/litegraph'
|
||||
import {
|
||||
LGraphEventMode,
|
||||
type Positionable,
|
||||
LGraphNode,
|
||||
Positionable,
|
||||
Reroute
|
||||
} from '@/lib/litegraph/src/litegraph'
|
||||
import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
|
||||
|
||||
159
tests-ui/tests/composables/graph/useCanvasInteractions.test.ts
Normal file
159
tests-ui/tests/composables/graph/useCanvasInteractions.test.ts
Normal file
@@ -0,0 +1,159 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import { useCanvasInteractions } from '@/composables/graph/useCanvasInteractions'
|
||||
import type { LGraphCanvas } from '@/lib/litegraph/src/litegraph'
|
||||
import { useSettingStore } from '@/platform/settings/settingStore'
|
||||
import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
|
||||
|
||||
// Mock stores
|
||||
vi.mock('@/renderer/core/canvas/canvasStore', () => {
|
||||
const getCanvas = vi.fn()
|
||||
const setCursorStyle = vi.fn()
|
||||
return {
|
||||
useCanvasStore: vi.fn(() => ({
|
||||
getCanvas,
|
||||
setCursorStyle
|
||||
}))
|
||||
}
|
||||
})
|
||||
vi.mock('@/platform/settings/settingStore', () => {
|
||||
const getFn = vi.fn()
|
||||
return { useSettingStore: vi.fn(() => ({ get: getFn })) }
|
||||
})
|
||||
vi.mock('@/scripts/app', () => ({
|
||||
app: {
|
||||
canvas: {
|
||||
canvas: {
|
||||
dispatchEvent: vi.fn()
|
||||
}
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
function createMockLGraphCanvas(read_only = true): LGraphCanvas {
|
||||
const mockCanvas: Partial<LGraphCanvas> = { read_only }
|
||||
return mockCanvas as LGraphCanvas
|
||||
}
|
||||
|
||||
function createMockPointerEvent(
|
||||
buttons: PointerEvent['buttons'] = 1
|
||||
): PointerEvent {
|
||||
const mockEvent: Partial<PointerEvent> = {
|
||||
buttons,
|
||||
preventDefault: vi.fn(),
|
||||
stopPropagation: vi.fn()
|
||||
}
|
||||
return mockEvent as PointerEvent
|
||||
}
|
||||
|
||||
function createMockWheelEvent(ctrlKey = false, metaKey = false): WheelEvent {
|
||||
const mockEvent: Partial<WheelEvent> = {
|
||||
ctrlKey,
|
||||
metaKey,
|
||||
preventDefault: vi.fn(),
|
||||
stopPropagation: vi.fn()
|
||||
}
|
||||
return mockEvent as WheelEvent
|
||||
}
|
||||
|
||||
describe('useCanvasInteractions', () => {
|
||||
beforeEach(() => {
|
||||
vi.resetAllMocks()
|
||||
})
|
||||
|
||||
describe('handlePointer', () => {
|
||||
it('should intercept left mouse events when canvas is read_only to enable space+drag navigation', () => {
|
||||
const { getCanvas } = useCanvasStore()
|
||||
const mockCanvas = createMockLGraphCanvas(true)
|
||||
vi.mocked(getCanvas).mockReturnValue(mockCanvas)
|
||||
|
||||
const { handlePointer } = useCanvasInteractions()
|
||||
|
||||
const mockEvent = createMockPointerEvent(1) // Left Mouse Button
|
||||
handlePointer(mockEvent)
|
||||
|
||||
expect(mockEvent.preventDefault).toHaveBeenCalled()
|
||||
expect(mockEvent.stopPropagation).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should forward middle mouse button events to canvas', () => {
|
||||
const { getCanvas } = useCanvasStore()
|
||||
const mockCanvas = createMockLGraphCanvas(false)
|
||||
vi.mocked(getCanvas).mockReturnValue(mockCanvas)
|
||||
const { handlePointer } = useCanvasInteractions()
|
||||
|
||||
const mockEvent = createMockPointerEvent(4) // Middle mouse button
|
||||
handlePointer(mockEvent)
|
||||
|
||||
expect(mockEvent.preventDefault).toHaveBeenCalled()
|
||||
expect(mockEvent.stopPropagation).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should not prevent default when canvas is not in read_only mode and not middle button', () => {
|
||||
const { getCanvas } = useCanvasStore()
|
||||
const mockCanvas = createMockLGraphCanvas(false)
|
||||
vi.mocked(getCanvas).mockReturnValue(mockCanvas)
|
||||
const { handlePointer } = useCanvasInteractions()
|
||||
|
||||
const mockEvent = createMockPointerEvent(1)
|
||||
handlePointer(mockEvent)
|
||||
|
||||
expect(mockEvent.preventDefault).not.toHaveBeenCalled()
|
||||
expect(mockEvent.stopPropagation).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should return early when canvas is null', () => {
|
||||
const { getCanvas } = useCanvasStore()
|
||||
vi.mocked(getCanvas).mockReturnValue(null as unknown as LGraphCanvas) // TODO: Fix misaligned types
|
||||
const { handlePointer } = useCanvasInteractions()
|
||||
|
||||
const mockEvent = createMockPointerEvent(1)
|
||||
handlePointer(mockEvent)
|
||||
|
||||
expect(getCanvas).toHaveBeenCalled()
|
||||
expect(mockEvent.preventDefault).not.toHaveBeenCalled()
|
||||
expect(mockEvent.stopPropagation).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
describe('handleWheel', () => {
|
||||
it('should forward ctrl+wheel events to canvas in standard nav mode', () => {
|
||||
const { get } = useSettingStore()
|
||||
vi.mocked(get).mockReturnValue('standard')
|
||||
|
||||
const { handleWheel } = useCanvasInteractions()
|
||||
|
||||
// Ctrl key pressed
|
||||
const mockEvent = createMockWheelEvent(true)
|
||||
|
||||
handleWheel(mockEvent)
|
||||
|
||||
expect(mockEvent.preventDefault).toHaveBeenCalled()
|
||||
expect(mockEvent.stopPropagation).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should forward all wheel events to canvas in legacy nav mode', () => {
|
||||
const { get } = useSettingStore()
|
||||
vi.mocked(get).mockReturnValue('legacy')
|
||||
const { handleWheel } = useCanvasInteractions()
|
||||
|
||||
const mockEvent = createMockWheelEvent()
|
||||
handleWheel(mockEvent)
|
||||
|
||||
expect(mockEvent.preventDefault).toHaveBeenCalled()
|
||||
expect(mockEvent.stopPropagation).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should not prevent default for regular wheel events in standard nav mode', () => {
|
||||
const { get } = useSettingStore()
|
||||
vi.mocked(get).mockReturnValue('standard')
|
||||
const { handleWheel } = useCanvasInteractions()
|
||||
|
||||
const mockEvent = createMockWheelEvent()
|
||||
handleWheel(mockEvent)
|
||||
|
||||
expect(mockEvent.preventDefault).not.toHaveBeenCalled()
|
||||
expect(mockEvent.stopPropagation).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1894,159 +1894,4 @@ describe('useNodePricing', () => {
|
||||
expect(getNodeDisplayPrice(missingDuration)).toBe('Token-based')
|
||||
})
|
||||
})
|
||||
|
||||
describe('dynamic pricing - WanTextToVideoApi', () => {
|
||||
it('should return $1.50 for 10s at 1080p', () => {
|
||||
const { getNodeDisplayPrice } = useNodePricing()
|
||||
const node = createMockNode('WanTextToVideoApi', [
|
||||
{ name: 'duration', value: '10' },
|
||||
{ name: 'size', value: '1080p: 4:3 (1632x1248)' }
|
||||
])
|
||||
|
||||
const price = getNodeDisplayPrice(node)
|
||||
expect(price).toBe('$1.50/Run') // 0.15 * 10
|
||||
})
|
||||
|
||||
it('should return $0.50 for 5s at 720p', () => {
|
||||
const { getNodeDisplayPrice } = useNodePricing()
|
||||
const node = createMockNode('WanTextToVideoApi', [
|
||||
{ name: 'duration', value: 5 },
|
||||
{ name: 'size', value: '720p: 16:9 (1280x720)' }
|
||||
])
|
||||
|
||||
const price = getNodeDisplayPrice(node)
|
||||
expect(price).toBe('$0.50/Run') // 0.10 * 5
|
||||
})
|
||||
|
||||
it('should return $0.15 for 3s at 480p', () => {
|
||||
const { getNodeDisplayPrice } = useNodePricing()
|
||||
const node = createMockNode('WanTextToVideoApi', [
|
||||
{ name: 'duration', value: '3' },
|
||||
{ name: 'size', value: '480p: 1:1 (624x624)' }
|
||||
])
|
||||
|
||||
const price = getNodeDisplayPrice(node)
|
||||
expect(price).toBe('$0.15/Run') // 0.05 * 3
|
||||
})
|
||||
|
||||
it('should fall back when widgets are missing', () => {
|
||||
const { getNodeDisplayPrice } = useNodePricing()
|
||||
const missingBoth = createMockNode('WanTextToVideoApi', [])
|
||||
const missingSize = createMockNode('WanTextToVideoApi', [
|
||||
{ name: 'duration', value: '5' }
|
||||
])
|
||||
const missingDuration = createMockNode('WanTextToVideoApi', [
|
||||
{ name: 'size', value: '1080p' }
|
||||
])
|
||||
|
||||
expect(getNodeDisplayPrice(missingBoth)).toBe('$0.05-0.15/second')
|
||||
expect(getNodeDisplayPrice(missingSize)).toBe('$0.05-0.15/second')
|
||||
expect(getNodeDisplayPrice(missingDuration)).toBe('$0.05-0.15/second')
|
||||
})
|
||||
|
||||
it('should fall back on invalid duration', () => {
|
||||
const { getNodeDisplayPrice } = useNodePricing()
|
||||
const node = createMockNode('WanTextToVideoApi', [
|
||||
{ name: 'duration', value: 'invalid' },
|
||||
{ name: 'size', value: '1080p' }
|
||||
])
|
||||
|
||||
const price = getNodeDisplayPrice(node)
|
||||
expect(price).toBe('$0.05-0.15/second')
|
||||
})
|
||||
|
||||
it('should fall back on unknown resolution', () => {
|
||||
const { getNodeDisplayPrice } = useNodePricing()
|
||||
const node = createMockNode('WanTextToVideoApi', [
|
||||
{ name: 'duration', value: '10' },
|
||||
{ name: 'size', value: '2K' }
|
||||
])
|
||||
|
||||
const price = getNodeDisplayPrice(node)
|
||||
expect(price).toBe('$0.05-0.15/second')
|
||||
})
|
||||
})
|
||||
|
||||
describe('dynamic pricing - WanImageToVideoApi', () => {
|
||||
it('should return $0.80 for 8s at 720p', () => {
|
||||
const { getNodeDisplayPrice } = useNodePricing()
|
||||
const node = createMockNode('WanImageToVideoApi', [
|
||||
{ name: 'duration', value: 8 },
|
||||
{ name: 'resolution', value: '720p' }
|
||||
])
|
||||
|
||||
const price = getNodeDisplayPrice(node)
|
||||
expect(price).toBe('$0.80/Run') // 0.10 * 8
|
||||
})
|
||||
|
||||
it('should return $0.60 for 12s at 480P', () => {
|
||||
const { getNodeDisplayPrice } = useNodePricing()
|
||||
const node = createMockNode('WanImageToVideoApi', [
|
||||
{ name: 'duration', value: '12' },
|
||||
{ name: 'resolution', value: '480P' }
|
||||
])
|
||||
|
||||
const price = getNodeDisplayPrice(node)
|
||||
expect(price).toBe('$0.60/Run') // 0.05 * 12
|
||||
})
|
||||
|
||||
it('should return $1.50 for 10s at 1080p', () => {
|
||||
const { getNodeDisplayPrice } = useNodePricing()
|
||||
const node = createMockNode('WanImageToVideoApi', [
|
||||
{ name: 'duration', value: '10' },
|
||||
{ name: 'resolution', value: '1080p' }
|
||||
])
|
||||
|
||||
const price = getNodeDisplayPrice(node)
|
||||
expect(price).toBe('$1.50/Run') // 0.15 * 10
|
||||
})
|
||||
|
||||
it('should handle "5s" string duration at 1080P', () => {
|
||||
const { getNodeDisplayPrice } = useNodePricing()
|
||||
const node = createMockNode('WanImageToVideoApi', [
|
||||
{ name: 'duration', value: '5s' },
|
||||
{ name: 'resolution', value: '1080P' }
|
||||
])
|
||||
|
||||
const price = getNodeDisplayPrice(node)
|
||||
expect(price).toBe('$0.75/Run') // 0.15 * 5
|
||||
})
|
||||
|
||||
it('should fall back when widgets are missing', () => {
|
||||
const { getNodeDisplayPrice } = useNodePricing()
|
||||
const missingBoth = createMockNode('WanImageToVideoApi', [])
|
||||
const missingRes = createMockNode('WanImageToVideoApi', [
|
||||
{ name: 'duration', value: '5' }
|
||||
])
|
||||
const missingDuration = createMockNode('WanImageToVideoApi', [
|
||||
{ name: 'resolution', value: '1080p' }
|
||||
])
|
||||
|
||||
expect(getNodeDisplayPrice(missingBoth)).toBe('$0.05-0.15/second')
|
||||
expect(getNodeDisplayPrice(missingRes)).toBe('$0.05-0.15/second')
|
||||
expect(getNodeDisplayPrice(missingDuration)).toBe('$0.05-0.15/second')
|
||||
})
|
||||
|
||||
it('should fall back on invalid duration', () => {
|
||||
const { getNodeDisplayPrice } = useNodePricing()
|
||||
const node = createMockNode('WanImageToVideoApi', [
|
||||
{ name: 'duration', value: 'invalid' },
|
||||
{ name: 'resolution', value: '720p' }
|
||||
])
|
||||
|
||||
const price = getNodeDisplayPrice(node)
|
||||
expect(price).toBe('$0.05-0.15/second')
|
||||
})
|
||||
|
||||
it('should fall back on unknown resolution', () => {
|
||||
const { getNodeDisplayPrice } = useNodePricing()
|
||||
const node = createMockNode('WanImageToVideoApi', [
|
||||
{ name: 'duration', value: '10' },
|
||||
{ name: 'resolution', value: 'weird-res' }
|
||||
])
|
||||
|
||||
const price = getNodeDisplayPrice(node)
|
||||
expect(price).toBe('$0.05-0.15/second')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -3,8 +3,8 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { ref } from 'vue'
|
||||
|
||||
import { usePacksSelection } from '@/composables/nodePack/usePacksSelection'
|
||||
import { useComfyManagerStore } from '@/stores/comfyManagerStore'
|
||||
import type { components } from '@/types/comfyRegistryTypes'
|
||||
import { useComfyManagerStore } from '@/workbench/extensions/manager/stores/comfyManagerStore'
|
||||
|
||||
vi.mock('vue-i18n', async () => {
|
||||
const actual = await vi.importActual('vue-i18n')
|
||||
|
||||
@@ -4,7 +4,7 @@ import { nextTick } from 'vue'
|
||||
|
||||
import { useConflictDetection } from '@/composables/useConflictDetection'
|
||||
import type { components } from '@/types/comfyRegistryTypes'
|
||||
import type { components as ManagerComponents } from '@/workbench/extensions/manager/types/generatedManagerTypes'
|
||||
import type { components as ManagerComponents } from '@/types/generatedManagerTypes'
|
||||
|
||||
type InstalledPacksResponse =
|
||||
ManagerComponents['schemas']['InstalledPacksResponse']
|
||||
@@ -27,7 +27,7 @@ vi.mock('@/scripts/api', () => ({
|
||||
}
|
||||
}))
|
||||
|
||||
vi.mock('@/workbench/extensions/manager/services/comfyManagerService', () => ({
|
||||
vi.mock('@/services/comfyManagerService', () => ({
|
||||
useComfyManagerService: vi.fn()
|
||||
}))
|
||||
|
||||
@@ -57,7 +57,7 @@ vi.mock('@/composables/nodePack/useInstalledPacks', () => ({
|
||||
}))
|
||||
}))
|
||||
|
||||
vi.mock('@/workbench/extensions/manager/stores/comfyManagerStore', () => ({
|
||||
vi.mock('@/stores/comfyManagerStore', () => ({
|
||||
useComfyManagerStore: vi.fn(() => ({
|
||||
isPackInstalled: vi.fn(),
|
||||
installedPacks: { value: [] }
|
||||
@@ -140,7 +140,7 @@ describe.skip('useConflictDetection with Registry Store', () => {
|
||||
|
||||
// Mock useComfyManagerService
|
||||
const { useComfyManagerService } = await import(
|
||||
'@/workbench/extensions/manager/services/comfyManagerService'
|
||||
'@/services/comfyManagerService'
|
||||
)
|
||||
vi.mocked(useComfyManagerService).mockReturnValue(
|
||||
mockComfyManagerService as any
|
||||
|
||||
@@ -4,11 +4,11 @@ import { computed, ref } from 'vue'
|
||||
|
||||
import { useImportFailedDetection } from '@/composables/useImportFailedDetection'
|
||||
import * as dialogService from '@/services/dialogService'
|
||||
import * as comfyManagerStore from '@/stores/comfyManagerStore'
|
||||
import * as conflictDetectionStore from '@/stores/conflictDetectionStore'
|
||||
import * as comfyManagerStore from '@/workbench/extensions/manager/stores/comfyManagerStore'
|
||||
|
||||
// Mock the stores and services
|
||||
vi.mock('@/workbench/extensions/manager/stores/comfyManagerStore')
|
||||
vi.mock('@/stores/comfyManagerStore')
|
||||
vi.mock('@/stores/conflictDetectionStore')
|
||||
vi.mock('@/services/dialogService')
|
||||
vi.mock('vue-i18n', async (importOriginal) => {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { ref } from 'vue'
|
||||
|
||||
import { useManagerQueue } from '@/workbench/extensions/manager/composables/useManagerQueue'
|
||||
import type { components } from '@/workbench/extensions/manager/types/generatedManagerTypes'
|
||||
import { useManagerQueue } from '@/composables/useManagerQueue'
|
||||
import { components } from '@/types/generatedManagerTypes'
|
||||
|
||||
// Mock dialog service
|
||||
vi.mock('@/services/dialogService', () => ({
|
||||
|
||||
@@ -2,13 +2,10 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { ref } from 'vue'
|
||||
|
||||
import { useFeatureFlags } from '@/composables/useFeatureFlags'
|
||||
import { ManagerUIState, useManagerState } from '@/composables/useManagerState'
|
||||
import { api } from '@/scripts/api'
|
||||
import { useExtensionStore } from '@/stores/extensionStore'
|
||||
import { useSystemStatsStore } from '@/stores/systemStatsStore'
|
||||
import {
|
||||
ManagerUIState,
|
||||
useManagerState
|
||||
} from '@/workbench/extensions/manager/composables/useManagerState'
|
||||
|
||||
// Mock dependencies
|
||||
vi.mock('@/scripts/api', () => ({
|
||||
@@ -59,10 +56,10 @@ describe('useManagerState', () => {
|
||||
})
|
||||
|
||||
describe('managerUIState property', () => {
|
||||
it('should return DISABLED state when --enable-manager is NOT present', () => {
|
||||
it('should return DISABLED state when --disable-manager is present', () => {
|
||||
vi.mocked(useSystemStatsStore).mockReturnValue({
|
||||
systemStats: ref({
|
||||
system: { argv: ['python', 'main.py'] } // No --enable-manager flag
|
||||
system: { argv: ['python', 'main.py', '--disable-manager'] }
|
||||
}),
|
||||
isInitialized: ref(true)
|
||||
} as any)
|
||||
@@ -79,14 +76,7 @@ describe('useManagerState', () => {
|
||||
it('should return LEGACY_UI state when --enable-manager-legacy-ui is present', () => {
|
||||
vi.mocked(useSystemStatsStore).mockReturnValue({
|
||||
systemStats: ref({
|
||||
system: {
|
||||
argv: [
|
||||
'python',
|
||||
'main.py',
|
||||
'--enable-manager',
|
||||
'--enable-manager-legacy-ui'
|
||||
]
|
||||
} // Both flags needed
|
||||
system: { argv: ['python', 'main.py', '--enable-manager-legacy-ui'] }
|
||||
}),
|
||||
isInitialized: ref(true)
|
||||
} as any)
|
||||
@@ -102,9 +92,7 @@ describe('useManagerState', () => {
|
||||
|
||||
it('should return NEW_UI state when client and server both support v4', () => {
|
||||
vi.mocked(useSystemStatsStore).mockReturnValue({
|
||||
systemStats: ref({
|
||||
system: { argv: ['python', 'main.py', '--enable-manager'] }
|
||||
}), // Need --enable-manager
|
||||
systemStats: ref({ system: { argv: ['python', 'main.py'] } }),
|
||||
isInitialized: ref(true)
|
||||
} as any)
|
||||
vi.mocked(api.getClientFeatureFlags).mockReturnValue({
|
||||
@@ -126,9 +114,7 @@ describe('useManagerState', () => {
|
||||
|
||||
it('should return LEGACY_UI state when server supports v4 but client does not', () => {
|
||||
vi.mocked(useSystemStatsStore).mockReturnValue({
|
||||
systemStats: ref({
|
||||
system: { argv: ['python', 'main.py', '--enable-manager'] }
|
||||
}), // Need --enable-manager
|
||||
systemStats: ref({ system: { argv: ['python', 'main.py'] } }),
|
||||
isInitialized: ref(true)
|
||||
} as any)
|
||||
vi.mocked(api.getClientFeatureFlags).mockReturnValue({
|
||||
@@ -150,9 +136,7 @@ describe('useManagerState', () => {
|
||||
|
||||
it('should return LEGACY_UI state when legacy manager extension exists', () => {
|
||||
vi.mocked(useSystemStatsStore).mockReturnValue({
|
||||
systemStats: ref({
|
||||
system: { argv: ['python', 'main.py', '--enable-manager'] }
|
||||
}), // Need --enable-manager
|
||||
systemStats: ref({ system: { argv: ['python', 'main.py'] } }),
|
||||
isInitialized: ref(true)
|
||||
} as any)
|
||||
vi.mocked(api.getClientFeatureFlags).mockReturnValue({})
|
||||
@@ -171,9 +155,7 @@ describe('useManagerState', () => {
|
||||
|
||||
it('should return NEW_UI state when server feature flags are undefined', () => {
|
||||
vi.mocked(useSystemStatsStore).mockReturnValue({
|
||||
systemStats: ref({
|
||||
system: { argv: ['python', 'main.py', '--enable-manager'] }
|
||||
}), // Need --enable-manager
|
||||
systemStats: ref({ system: { argv: ['python', 'main.py'] } }),
|
||||
isInitialized: ref(true)
|
||||
} as any)
|
||||
vi.mocked(api.getClientFeatureFlags).mockReturnValue({})
|
||||
@@ -193,9 +175,7 @@ describe('useManagerState', () => {
|
||||
|
||||
it('should return LEGACY_UI state when server does not support v4', () => {
|
||||
vi.mocked(useSystemStatsStore).mockReturnValue({
|
||||
systemStats: ref({
|
||||
system: { argv: ['python', 'main.py', '--enable-manager'] }
|
||||
}), // Need --enable-manager
|
||||
systemStats: ref({ system: { argv: ['python', 'main.py'] } }),
|
||||
isInitialized: ref(true)
|
||||
} as any)
|
||||
vi.mocked(api.getClientFeatureFlags).mockReturnValue({})
|
||||
@@ -232,17 +212,14 @@ describe('useManagerState', () => {
|
||||
|
||||
const managerState = useManagerState()
|
||||
|
||||
// When systemStats is null, we can't check for --enable-manager flag, so manager is disabled
|
||||
expect(managerState.managerUIState.value).toBe(ManagerUIState.DISABLED)
|
||||
expect(managerState.managerUIState.value).toBe(ManagerUIState.NEW_UI)
|
||||
})
|
||||
})
|
||||
|
||||
describe('helper properties', () => {
|
||||
it('isManagerEnabled should return true when state is not DISABLED', () => {
|
||||
vi.mocked(useSystemStatsStore).mockReturnValue({
|
||||
systemStats: ref({
|
||||
system: { argv: ['python', 'main.py', '--enable-manager'] }
|
||||
}), // Need --enable-manager
|
||||
systemStats: ref({ system: { argv: ['python', 'main.py'] } }),
|
||||
isInitialized: ref(true)
|
||||
} as any)
|
||||
vi.mocked(api.getClientFeatureFlags).mockReturnValue({
|
||||
@@ -260,7 +237,7 @@ describe('useManagerState', () => {
|
||||
it('isManagerEnabled should return false when state is DISABLED', () => {
|
||||
vi.mocked(useSystemStatsStore).mockReturnValue({
|
||||
systemStats: ref({
|
||||
system: { argv: ['python', 'main.py'] } // No --enable-manager flag means disabled
|
||||
system: { argv: ['python', 'main.py', '--disable-manager'] }
|
||||
}),
|
||||
isInitialized: ref(true)
|
||||
} as any)
|
||||
@@ -275,9 +252,7 @@ describe('useManagerState', () => {
|
||||
|
||||
it('isNewManagerUI should return true when state is NEW_UI', () => {
|
||||
vi.mocked(useSystemStatsStore).mockReturnValue({
|
||||
systemStats: ref({
|
||||
system: { argv: ['python', 'main.py', '--enable-manager'] }
|
||||
}), // Need --enable-manager
|
||||
systemStats: ref({ system: { argv: ['python', 'main.py'] } }),
|
||||
isInitialized: ref(true)
|
||||
} as any)
|
||||
vi.mocked(api.getClientFeatureFlags).mockReturnValue({
|
||||
@@ -295,14 +270,7 @@ describe('useManagerState', () => {
|
||||
it('isLegacyManagerUI should return true when state is LEGACY_UI', () => {
|
||||
vi.mocked(useSystemStatsStore).mockReturnValue({
|
||||
systemStats: ref({
|
||||
system: {
|
||||
argv: [
|
||||
'python',
|
||||
'main.py',
|
||||
'--enable-manager',
|
||||
'--enable-manager-legacy-ui'
|
||||
]
|
||||
} // Both flags needed
|
||||
system: { argv: ['python', 'main.py', '--enable-manager-legacy-ui'] }
|
||||
}),
|
||||
isInitialized: ref(true)
|
||||
} as any)
|
||||
@@ -317,9 +285,7 @@ describe('useManagerState', () => {
|
||||
|
||||
it('shouldShowInstallButton should return true only for NEW_UI', () => {
|
||||
vi.mocked(useSystemStatsStore).mockReturnValue({
|
||||
systemStats: ref({
|
||||
system: { argv: ['python', 'main.py', '--enable-manager'] }
|
||||
}), // Need --enable-manager
|
||||
systemStats: ref({ system: { argv: ['python', 'main.py'] } }),
|
||||
isInitialized: ref(true)
|
||||
} as any)
|
||||
vi.mocked(api.getClientFeatureFlags).mockReturnValue({
|
||||
@@ -336,9 +302,7 @@ describe('useManagerState', () => {
|
||||
|
||||
it('shouldShowManagerButtons should return true when not DISABLED', () => {
|
||||
vi.mocked(useSystemStatsStore).mockReturnValue({
|
||||
systemStats: ref({
|
||||
system: { argv: ['python', 'main.py', '--enable-manager'] }
|
||||
}), // Need --enable-manager
|
||||
systemStats: ref({ system: { argv: ['python', 'main.py'] } }),
|
||||
isInitialized: ref(true)
|
||||
} as any)
|
||||
vi.mocked(api.getClientFeatureFlags).mockReturnValue({
|
||||
|
||||
@@ -5,9 +5,9 @@ import { useMissingNodes } from '@/composables/nodePack/useMissingNodes'
|
||||
import { useWorkflowPacks } from '@/composables/nodePack/useWorkflowPacks'
|
||||
import type { LGraphNode } from '@/lib/litegraph/src/litegraph'
|
||||
import { app } from '@/scripts/app'
|
||||
import { useComfyManagerStore } from '@/stores/comfyManagerStore'
|
||||
import { useNodeDefStore } from '@/stores/nodeDefStore'
|
||||
import { collectAllNodes } from '@/utils/graphTraversalUtil'
|
||||
import { useComfyManagerStore } from '@/workbench/extensions/manager/stores/comfyManagerStore'
|
||||
|
||||
// Mock Vue's onMounted to execute immediately for testing
|
||||
vi.mock('vue', async () => {
|
||||
@@ -23,7 +23,7 @@ vi.mock('@/composables/nodePack/useWorkflowPacks', () => ({
|
||||
useWorkflowPacks: vi.fn()
|
||||
}))
|
||||
|
||||
vi.mock('@/workbench/extensions/manager/stores/comfyManagerStore', () => ({
|
||||
vi.mock('@/stores/comfyManagerStore', () => ({
|
||||
useComfyManagerStore: vi.fn()
|
||||
}))
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import { useNodeChatHistory } from '@/composables/node/useNodeChatHistory'
|
||||
import type { LGraphNode } from '@/lib/litegraph/src/litegraph'
|
||||
import { LGraphNode } from '@/lib/litegraph/src/litegraph'
|
||||
|
||||
vi.mock(
|
||||
'@/renderer/extensions/vueNodes/widgets/composables/useChatHistoryWidget',
|
||||
|
||||
@@ -3,7 +3,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { nextTick } from 'vue'
|
||||
|
||||
import { useServerLogs } from '@/composables/useServerLogs'
|
||||
import type { LogsWsMessage } from '@/schemas/apiSchema'
|
||||
import { LogsWsMessage } from '@/schemas/apiSchema'
|
||||
import { api } from '@/scripts/api'
|
||||
|
||||
vi.mock('@/scripts/api', () => ({
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
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 { useComfyManagerStore } from '@/workbench/extensions/manager/stores/comfyManagerStore'
|
||||
import { useComfyManagerStore } from '@/stores/comfyManagerStore'
|
||||
// Import mocked utils
|
||||
import { compareVersions, isSemVer } from '@/utils/formatUtil'
|
||||
|
||||
// Mock Vue's onMounted to execute immediately for testing
|
||||
vi.mock('vue', async () => {
|
||||
@@ -20,20 +21,20 @@ vi.mock('@/composables/nodePack/useInstalledPacks', () => ({
|
||||
useInstalledPacks: vi.fn()
|
||||
}))
|
||||
|
||||
vi.mock('@/workbench/extensions/manager/stores/comfyManagerStore', () => ({
|
||||
vi.mock('@/stores/comfyManagerStore', () => ({
|
||||
useComfyManagerStore: vi.fn()
|
||||
}))
|
||||
|
||||
vi.mock('semver', () => ({
|
||||
compare: vi.fn(),
|
||||
valid: vi.fn()
|
||||
vi.mock('@/utils/formatUtil', () => ({
|
||||
compareVersions: vi.fn(),
|
||||
isSemVer: vi.fn()
|
||||
}))
|
||||
|
||||
const mockUseInstalledPacks = vi.mocked(useInstalledPacks)
|
||||
const mockUseComfyManagerStore = vi.mocked(useComfyManagerStore)
|
||||
|
||||
const mockSemverCompare = vi.mocked(compare)
|
||||
const mockSemverValid = vi.mocked(valid)
|
||||
const mockCompareVersions = vi.mocked(compareVersions)
|
||||
const mockIsSemVer = vi.mocked(isSemVer)
|
||||
|
||||
describe('useUpdateAvailableNodes', () => {
|
||||
const mockInstalledPacks = [
|
||||
@@ -85,19 +86,19 @@ describe('useUpdateAvailableNodes', () => {
|
||||
}
|
||||
})
|
||||
|
||||
mockSemverValid.mockImplementation((version) => {
|
||||
return version &&
|
||||
typeof version === 'string' &&
|
||||
!version.includes('nightly')
|
||||
? version
|
||||
: null
|
||||
})
|
||||
mockIsSemVer.mockImplementation(
|
||||
(version: string): version is `${number}.${number}.${number}` => {
|
||||
return !version.includes('nightly')
|
||||
}
|
||||
)
|
||||
|
||||
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
|
||||
})
|
||||
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
|
||||
}
|
||||
)
|
||||
|
||||
mockUseComfyManagerStore.mockReturnValue({
|
||||
isPackInstalled: mockIsPackInstalled,
|
||||
@@ -321,10 +322,10 @@ describe('useUpdateAvailableNodes', () => {
|
||||
// Access the computed to trigger the logic
|
||||
expect(updateAvailableNodePacks.value).toBeDefined()
|
||||
|
||||
expect(mockSemverCompare).toHaveBeenCalledWith('2.0.0', '1.0.0')
|
||||
expect(mockCompareVersions).toHaveBeenCalledWith('2.0.0', '1.0.0')
|
||||
})
|
||||
|
||||
it('calls semver.valid to check nightly versions', () => {
|
||||
it('calls isSemVer to check nightly versions', () => {
|
||||
mockUseInstalledPacks.mockReturnValue({
|
||||
installedPacks: ref([mockInstalledPacks[2]]), // pack-3: nightly
|
||||
isLoading: ref(false),
|
||||
@@ -337,7 +338,7 @@ describe('useUpdateAvailableNodes', () => {
|
||||
// Access the computed to trigger the logic
|
||||
expect(updateAvailableNodePacks.value).toBeDefined()
|
||||
|
||||
expect(mockSemverValid).toHaveBeenCalledWith('nightly-abc123')
|
||||
expect(mockIsSemVer).toHaveBeenCalledWith('nightly-abc123')
|
||||
})
|
||||
|
||||
it('calls isPackInstalled for each pack', () => {
|
||||
|
||||
Reference in New Issue
Block a user