[manager] Update tests for new manager API

Updated tests for manager queue composable, server logs composable, and manager store to work with the new API signatures and functionality.
This commit is contained in:
bymyself
2025-06-13 14:00:10 -07:00
committed by Jin Yi
parent 5765e0f105
commit a28aa80370
3 changed files with 183 additions and 275 deletions

View File

@@ -24,22 +24,22 @@ describe('useServerLogs', () => {
}) })
it('should initialize with empty logs array', () => { it('should initialize with empty logs array', () => {
const { logs } = useServerLogs() const { logs } = useServerLogs({ ui_id: 'test-ui-id' })
expect(logs.value).toEqual([]) expect(logs.value).toEqual([])
}) })
it('should not subscribe to logs by default', () => { it('should not subscribe to logs by default', () => {
useServerLogs() useServerLogs({ ui_id: 'test-ui-id' })
expect(api.subscribeLogs).not.toHaveBeenCalled() expect(api.subscribeLogs).not.toHaveBeenCalled()
}) })
it('should subscribe to logs when immediate is true', () => { it('should subscribe to logs when immediate is true', () => {
useServerLogs({ immediate: true }) useServerLogs({ ui_id: 'test-ui-id', immediate: true })
expect(api.subscribeLogs).toHaveBeenCalledWith(true) expect(api.subscribeLogs).toHaveBeenCalledWith(true)
}) })
it('should start listening when startListening is called', async () => { it('should start listening when startListening is called', async () => {
const { startListening } = useServerLogs() const { startListening } = useServerLogs({ ui_id: 'test-ui-id' })
await startListening() await startListening()
@@ -47,7 +47,9 @@ describe('useServerLogs', () => {
}) })
it('should stop listening when stopListening is called', async () => { it('should stop listening when stopListening is called', async () => {
const { startListening, stopListening } = useServerLogs() const { startListening, stopListening } = useServerLogs({
ui_id: 'test-ui-id'
})
await startListening() await startListening()
await stopListening() await stopListening()
@@ -56,7 +58,7 @@ describe('useServerLogs', () => {
}) })
it('should register event listener when starting', async () => { it('should register event listener when starting', async () => {
const { startListening } = useServerLogs() const { startListening } = useServerLogs({ ui_id: 'test-ui-id' })
await startListening() await startListening()
@@ -68,7 +70,7 @@ describe('useServerLogs', () => {
}) })
it('should handle log messages correctly', async () => { it('should handle log messages correctly', async () => {
const { logs, startListening } = useServerLogs() const { logs, startListening } = useServerLogs({ ui_id: 'test-ui-id' })
await startListening() await startListening()
@@ -93,6 +95,7 @@ describe('useServerLogs', () => {
it('should use the message filter if provided', async () => { it('should use the message filter if provided', async () => {
const { logs, startListening } = useServerLogs({ const { logs, startListening } = useServerLogs({
ui_id: 'test-ui-id',
messageFilter: (msg) => msg !== 'remove me' messageFilter: (msg) => msg !== 'remove me'
}) })

View File

@@ -1,5 +1,5 @@
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { nextTick } from 'vue' import { nextTick, ref } from 'vue'
import { useManagerQueue } from '@/composables/useManagerQueue' import { useManagerQueue } from '@/composables/useManagerQueue'
import { api } from '@/scripts/api' import { api } from '@/scripts/api'
@@ -12,32 +12,39 @@ vi.mock('@/scripts/api', () => ({
} }
})) }))
vi.mock('@/services/comfyManagerService', () => ({
useComfyManagerService: vi.fn(() => ({
getTaskQueue: vi.fn().mockResolvedValue({
queue_running: [],
queue_pending: []
}),
getTaskHistory: vi.fn().mockResolvedValue({}),
clearTaskHistory: vi.fn().mockResolvedValue(null),
deleteTaskHistoryItems: vi.fn().mockResolvedValue(null)
}))
}))
vi.mock('@/services/dialogService', () => ({
useDialogService: vi.fn(() => ({
showManagerProgressDialog: vi.fn()
}))
}))
describe('useManagerQueue', () => { describe('useManagerQueue', () => {
const createMockTask = (result: any = 'result') => ({ let taskHistory: any
task: vi.fn().mockResolvedValue(result), let taskQueue: any
onComplete: vi.fn() let installedPacks: any
})
const createQueueWithMockTask = () => {
const queue = useManagerQueue()
const mockTask = createMockTask()
queue.enqueueTask(mockTask)
return { queue, mockTask }
}
const getEventListenerCallback = () =>
vi.mocked(api.addEventListener).mock.calls[0][1]
const simulateServerStatus = async (status: 'all-done' | 'in_progress') => {
const event = new CustomEvent('cm-queue-status', {
detail: { status }
})
getEventListenerCallback()!(event as any)
await nextTick()
}
beforeEach(() => { beforeEach(() => {
vi.clearAllMocks() vi.clearAllMocks()
taskHistory = ref({})
taskQueue = ref({
history: {},
running_queue: [],
pending_queue: [],
installed_packs: {}
})
installedPacks = ref({})
}) })
afterEach(() => { afterEach(() => {
@@ -46,284 +53,182 @@ describe('useManagerQueue', () => {
describe('initialization', () => { describe('initialization', () => {
it('should initialize with empty queue and DONE status', () => { it('should initialize with empty queue and DONE status', () => {
const queue = useManagerQueue() const queue = useManagerQueue(taskHistory, taskQueue, installedPacks)
expect(queue.queueLength.value).toBe(0) expect(queue.queueLength.value).toBe(0)
expect(queue.statusMessage.value).toBe('all-done')
expect(queue.allTasksDone.value).toBe(true) expect(queue.allTasksDone.value).toBe(true)
}) })
it('should set up event listeners on creation', () => {
useManagerQueue(taskHistory, taskQueue, installedPacks)
expect(api.addEventListener).toHaveBeenCalled()
})
}) })
describe('queue management', () => { describe('processing state handling', () => {
it('should add tasks to the queue', () => { it('should update processing state based on queue length', async () => {
const queue = useManagerQueue() const queue = useManagerQueue(taskHistory, taskQueue, installedPacks)
const mockTask = createMockTask()
queue.enqueueTask(mockTask) // Initially empty queue
expect(queue.isProcessing.value).toBe(false)
expect(queue.allTasksDone.value).toBe(true)
expect(queue.queueLength.value).toBe(1) // Add tasks to queue
taskQueue.value.running_queue = [{ id: 'task1' } as any]
taskQueue.value.pending_queue = [{ id: 'task2' } as any]
// Force reactivity update
await nextTick()
expect(queue.queueLength.value).toBe(2)
})
})
describe('task state management', () => {
it('should reflect task queue state changes', async () => {
const queue = useManagerQueue(taskHistory, taskQueue, installedPacks)
// Add running tasks
taskQueue.value.running_queue = [{ id: 'task1' } as any]
taskQueue.value.pending_queue = [{ id: 'task2' } as any]
await nextTick()
expect(queue.queueLength.value).toBe(2)
expect(queue.allTasksDone.value).toBe(false) expect(queue.allTasksDone.value).toBe(false)
}) })
it('should clear the queue when clearQueue is called', () => { it('should handle empty queue state', async () => {
const queue = useManagerQueue() const queue = useManagerQueue(taskHistory, taskQueue, installedPacks)
// Add some tasks taskQueue.value.running_queue = []
queue.enqueueTask(createMockTask()) taskQueue.value.pending_queue = []
queue.enqueueTask(createMockTask())
expect(queue.queueLength.value).toBe(2) await nextTick()
// Clear the queue
queue.clearQueue()
expect(queue.queueLength.value).toBe(0) expect(queue.queueLength.value).toBe(0)
expect(queue.allTasksDone.value).toBe(true) expect(queue.allTasksDone.value).toBe(true)
}) })
}) })
describe('server status handling', () => { describe('queue data management', () => {
it('should update server status when receiving websocket events', async () => { it('should provide access to task queue state', async () => {
const queue = useManagerQueue() taskQueue.value.running_queue = [{ id: 'task1' } as any]
taskQueue.value.pending_queue = [
{ id: 'task2' },
{ id: 'task3' }
] as any[]
await simulateServerStatus('in_progress') const queue = useManagerQueue(taskHistory, taskQueue, installedPacks)
expect(queue.statusMessage.value).toBe('in_progress')
expect(queue.allTasksDone.value).toBe(false)
})
it('should handle invalid status values gracefully', async () => {
const queue = useManagerQueue()
// Simulate an invalid status
const event = new CustomEvent('cm-queue-status', {
detail: null as any
})
getEventListenerCallback()!(event)
await nextTick() await nextTick()
// Should maintain the default status expect(queue.taskQueue.value.running_queue).toEqual([{ id: 'task1' }])
expect(queue.statusMessage.value).toBe('all-done') expect(queue.taskQueue.value.pending_queue).toEqual([
}) { id: 'task2' },
{ id: 'task3' }
it('should handle missing status property gracefully', async () => {
const queue = useManagerQueue()
// Simulate a detail object without status property
const event = new CustomEvent('cm-queue-status', {
detail: { someOtherProperty: 'value' } as any
})
getEventListenerCallback()!(event)
await nextTick()
// Should maintain the default status
expect(queue.statusMessage.value).toBe('all-done')
})
})
describe('task execution', () => {
it('should start the next task when server is idle and queue has items', async () => {
const { queue, mockTask } = createQueueWithMockTask()
await simulateServerStatus('all-done')
// Task should have been started
expect(mockTask.task).toHaveBeenCalled()
expect(queue.queueLength.value).toBe(0)
})
it('should execute onComplete callback when task completes and server becomes idle', async () => {
const { mockTask } = createQueueWithMockTask()
// Start the task
await simulateServerStatus('all-done')
expect(mockTask.task).toHaveBeenCalled()
// Simulate task completion
await mockTask.task.mock.results[0].value
// Simulate server cycle (in_progress -> done)
await simulateServerStatus('in_progress')
expect(mockTask.onComplete).not.toHaveBeenCalled()
await simulateServerStatus('all-done')
expect(mockTask.onComplete).toHaveBeenCalled()
})
it('should handle tasks without onComplete callback', async () => {
const queue = useManagerQueue()
const mockTask = { task: vi.fn().mockResolvedValue('result') }
queue.enqueueTask(mockTask)
// Start the task
await simulateServerStatus('all-done')
expect(mockTask.task).toHaveBeenCalled()
// Simulate task completion
await mockTask.task.mock.results[0].value
// Simulate server cycle
await simulateServerStatus('in_progress')
await simulateServerStatus('all-done')
// Should not throw errors even without onComplete
expect(queue.allTasksDone.value).toBe(true)
})
it('should process multiple tasks in sequence', async () => {
const queue = useManagerQueue()
const mockTask1 = createMockTask('result1')
const mockTask2 = createMockTask('result2')
// Add tasks to the queue
queue.enqueueTask(mockTask1)
queue.enqueueTask(mockTask2)
expect(queue.queueLength.value).toBe(2)
// Process first task
await simulateServerStatus('all-done')
expect(mockTask1.task).toHaveBeenCalled()
expect(queue.queueLength.value).toBe(1)
// Complete first task
await mockTask1.task.mock.results[0].value
await simulateServerStatus('in_progress')
await simulateServerStatus('all-done')
expect(mockTask1.onComplete).toHaveBeenCalled()
// Process second task
expect(mockTask2.task).toHaveBeenCalled()
expect(queue.queueLength.value).toBe(0)
// Complete second task
await mockTask2.task.mock.results[0].value
await simulateServerStatus('in_progress')
await simulateServerStatus('all-done')
expect(mockTask2.onComplete).toHaveBeenCalled()
// Queue should be empty and all tasks done
expect(queue.queueLength.value).toBe(0)
expect(queue.allTasksDone.value).toBe(true)
})
it('should handle task that returns rejected promise', async () => {
const queue = useManagerQueue()
const mockTask = {
task: vi.fn().mockRejectedValue(new Error('Task failed')),
onComplete: vi.fn()
}
queue.enqueueTask(mockTask)
// Start the task
await simulateServerStatus('all-done')
expect(mockTask.task).toHaveBeenCalled()
// Let the promise rejection happen
try {
await mockTask.task()
} catch (e) {
// Ignore the error
}
// Simulate server cycle
await simulateServerStatus('in_progress')
await simulateServerStatus('all-done')
// onComplete should still be called for failed tasks
expect(mockTask.onComplete).toHaveBeenCalled()
})
it('should handle multiple multiple tasks enqueued at once while server busy', async () => {
const queue = useManagerQueue()
const mockTask1 = createMockTask()
const mockTask2 = createMockTask()
const mockTask3 = createMockTask()
// Three tasks enqueued at once
await simulateServerStatus('in_progress')
await Promise.all([
queue.enqueueTask(mockTask1),
queue.enqueueTask(mockTask2),
queue.enqueueTask(mockTask3)
]) ])
expect(queue.queueLength.value).toBe(3)
})
// Task 1 it('should provide access to task history', async () => {
await simulateServerStatus('all-done') const mockHistory = {
expect(mockTask1.task).toHaveBeenCalled() task1: { result: 'success', timestamp: '2023-01-01' },
task2: { result: 'error', timestamp: '2023-01-02' }
}
taskHistory.value = mockHistory as any
// Verify state of onComplete callbacks const queue = useManagerQueue(taskHistory, taskQueue, installedPacks)
expect(mockTask1.onComplete).toHaveBeenCalled() await nextTick()
expect(mockTask2.onComplete).not.toHaveBeenCalled()
expect(mockTask3.onComplete).not.toHaveBeenCalled()
// Verify state of queue expect(queue.taskHistory.value).toEqual(mockHistory)
expect(queue.queueLength.value).toBe(2) expect(queue.historyCount.value).toBe(2)
expect(queue.allTasksDone.value).toBe(false) })
// Task 2 it('should handle empty state gracefully', async () => {
await simulateServerStatus('in_progress') taskQueue.value.running_queue = []
await simulateServerStatus('all-done') taskQueue.value.pending_queue = []
expect(mockTask2.task).toHaveBeenCalled() taskHistory.value = {}
// Verify state of onComplete callbacks const queue = useManagerQueue(taskHistory, taskQueue, installedPacks)
expect(mockTask2.onComplete).toHaveBeenCalled() await nextTick()
expect(mockTask3.onComplete).not.toHaveBeenCalled()
// Verify state of queue
expect(queue.queueLength.value).toBe(1)
expect(queue.allTasksDone.value).toBe(false)
// Task 3
await simulateServerStatus('in_progress')
await simulateServerStatus('all-done')
// Verify state of onComplete callbacks
expect(mockTask3.task).toHaveBeenCalled()
expect(mockTask3.onComplete).toHaveBeenCalled()
// Verify state of queue
expect(queue.queueLength.value).toBe(0) expect(queue.queueLength.value).toBe(0)
expect(queue.historyCount.value).toBe(0)
})
})
describe('state management', () => {
it('should provide reactive task history', async () => {
const queue = useManagerQueue(taskHistory, taskQueue, installedPacks)
taskHistory.value = {
task1: { result: 'success' } as any,
task2: { result: 'error' } as any
}
await nextTick()
expect(queue.taskHistory.value).toEqual({
task1: { result: 'success' },
task2: { result: 'error' }
})
expect(queue.historyCount.value).toBe(2)
})
it('should provide reactive installed packs', async () => {
installedPacks.value = {
pack1: { version: '1.0' },
pack2: { version: '2.0' }
}
await nextTick()
// The composable should have access to installedPacks through the parameter
expect(installedPacks.value).toEqual({
pack1: { version: '1.0' },
pack2: { version: '2.0' }
})
})
})
describe('computed properties', () => {
it('should correctly compute allTasksDone', async () => {
const queue = useManagerQueue(taskHistory, taskQueue, installedPacks)
// Empty queue = all done
expect(queue.allTasksDone.value).toBe(true)
// Add pending tasks
taskQueue.value.pending_queue = [{ id: 'task1' } as any]
await nextTick()
expect(queue.allTasksDone.value).toBe(false)
// Clear queue
taskQueue.value.running_queue = []
taskQueue.value.pending_queue = []
await nextTick()
expect(queue.allTasksDone.value).toBe(true) expect(queue.allTasksDone.value).toBe(true)
}) })
it('should handle adding tasks while processing is in progress', async () => { it('should correctly compute queueLength', async () => {
const queue = useManagerQueue() const queue = useManagerQueue(taskHistory, taskQueue, installedPacks)
const mockTask1 = createMockTask()
const mockTask2 = createMockTask()
// Add first task and start processing expect(queue.queueLength.value).toBe(0)
queue.enqueueTask(mockTask1)
await simulateServerStatus('all-done')
expect(mockTask1.task).toHaveBeenCalled()
// Add second task while first is processing taskQueue.value.running_queue = [{ id: 'task1' } as any]
queue.enqueueTask(mockTask2) taskQueue.value.pending_queue = [
expect(queue.queueLength.value).toBe(1) { id: 'task2' } as any,
{ id: 'task3' } as any
]
// Complete first task await nextTick()
await mockTask1.task.mock.results[0].value
await simulateServerStatus('in_progress')
await simulateServerStatus('all-done')
// Second task should now be processed expect(queue.queueLength.value).toBe(3)
expect(mockTask2.task).toHaveBeenCalled()
})
it('should handle server status changes without tasks in queue', async () => {
const queue = useManagerQueue()
// Cycle server status without any tasks
await simulateServerStatus('in_progress')
await simulateServerStatus('all-done')
await simulateServerStatus('in_progress')
await simulateServerStatus('all-done')
// Should not cause any errors
expect(queue.allTasksDone.value).toBe(true)
}) })
}) })
}) })

View File

@@ -4,10 +4,10 @@ import { nextTick, ref } from 'vue'
import { useComfyManagerService } from '@/services/comfyManagerService' import { useComfyManagerService } from '@/services/comfyManagerService'
import { useComfyManagerStore } from '@/stores/comfyManagerStore' import { useComfyManagerStore } from '@/stores/comfyManagerStore'
import { import { components } from '@/types/generatedManagerTypes'
InstalledPacksResponse,
ManagerPackInstalled type InstalledPacksResponse = components['schemas']['InstalledPacksResponse']
} from '@/types/comfyManagerTypes' type ManagerPackInstalled = components['schemas']['ManagerPackInstalled']
vi.mock('@/services/comfyManagerService', () => ({ vi.mock('@/services/comfyManagerService', () => ({
useComfyManagerService: vi.fn() useComfyManagerService: vi.fn()