mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-04 07:00:23 +00:00
Implements Jobs API endpoints (/jobs) for cloud distribution to replace history_v2 API, providing 99.998% memory reduction per item. Key changes: - Jobs API types, schemas, and fetchers for list and detail endpoints - Adapter to convert Jobs API format to TaskItem format - Lazy loading for full outputs when loading workflows - hasOnlyPreviewOutputs() detection for preview-only tasks - Feature flag to toggle between Jobs API and history_v2 Implementation details: - List endpoint: Returns preview_output only (100-200 bytes per job) - Detail endpoint: Returns full workflow and outputs on demand - Cloud builds use /jobs?status=completed for history view - Desktop builds unchanged (still use history_v1) - 21 unit and integration tests (all passing) Memory optimization: - Old: 300-600KB per history item (full outputs) - New: 100-200 bytes per history item (preview only) - Reduction: 99.998% Co-Authored-By: Claude <noreply@anthropic.com>
102 lines
3.3 KiB
TypeScript
102 lines
3.3 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
import { computed, ref } from 'vue'
|
|
import type { ComputedRef } from 'vue'
|
|
|
|
import type { TaskItemImpl } from '@/stores/queueStore'
|
|
import type { JobErrorDialogService } from '@/components/queue/job/useJobErrorReporting'
|
|
import * as jobErrorReporting from '@/components/queue/job/useJobErrorReporting'
|
|
|
|
/**
|
|
* Creates a mock TaskItemImpl with an error message.
|
|
*/
|
|
const createTaskWithError = (errorMessage?: string): TaskItemImpl =>
|
|
({ errorMessage }) as unknown as TaskItemImpl
|
|
|
|
describe('extractErrorMessage', () => {
|
|
it('returns null when task is null', () => {
|
|
expect(jobErrorReporting.extractErrorMessage(null)).toBeNull()
|
|
})
|
|
|
|
it('returns null when errorMessage is undefined', () => {
|
|
expect(
|
|
jobErrorReporting.extractErrorMessage(createTaskWithError())
|
|
).toBeNull()
|
|
})
|
|
|
|
it('returns the error message when present', () => {
|
|
expect(
|
|
jobErrorReporting.extractErrorMessage(
|
|
createTaskWithError('Something failed')
|
|
)
|
|
).toBe('Something failed')
|
|
})
|
|
})
|
|
|
|
describe('useJobErrorReporting', () => {
|
|
let taskState = ref<TaskItemImpl | null>(null)
|
|
let taskForJob: ComputedRef<TaskItemImpl | null>
|
|
let copyToClipboard: ReturnType<typeof vi.fn>
|
|
let showErrorDialog: ReturnType<typeof vi.fn>
|
|
let dialog: JobErrorDialogService
|
|
let composable: ReturnType<typeof jobErrorReporting.useJobErrorReporting>
|
|
|
|
beforeEach(() => {
|
|
taskState = ref<TaskItemImpl | null>(null)
|
|
taskForJob = computed(() => taskState.value)
|
|
copyToClipboard = vi.fn()
|
|
showErrorDialog = vi.fn()
|
|
dialog = { showErrorDialog }
|
|
composable = jobErrorReporting.useJobErrorReporting({
|
|
taskForJob,
|
|
copyToClipboard,
|
|
dialog
|
|
})
|
|
})
|
|
|
|
afterEach(() => {
|
|
vi.restoreAllMocks()
|
|
})
|
|
|
|
it('exposes a computed message that reflects the current task error', () => {
|
|
taskState.value = createTaskWithError('First failure')
|
|
expect(composable.errorMessageValue.value).toBe('First failure')
|
|
|
|
taskState.value = createTaskWithError('Second failure')
|
|
expect(composable.errorMessageValue.value).toBe('Second failure')
|
|
})
|
|
|
|
it('returns empty string when no error message', () => {
|
|
taskState.value = createTaskWithError()
|
|
expect(composable.errorMessageValue.value).toBe('')
|
|
})
|
|
|
|
it('only calls the copy handler when a message exists', () => {
|
|
taskState.value = createTaskWithError('Clipboard failure')
|
|
composable.copyErrorMessage()
|
|
expect(copyToClipboard).toHaveBeenCalledTimes(1)
|
|
expect(copyToClipboard).toHaveBeenCalledWith('Clipboard failure')
|
|
|
|
copyToClipboard.mockClear()
|
|
taskState.value = createTaskWithError()
|
|
composable.copyErrorMessage()
|
|
expect(copyToClipboard).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('shows error dialog with the error message', () => {
|
|
taskState.value = createTaskWithError('Queue job error')
|
|
composable.reportJobError()
|
|
|
|
expect(showErrorDialog).toHaveBeenCalledTimes(1)
|
|
const [errorArg, optionsArg] = showErrorDialog.mock.calls[0]
|
|
expect(errorArg).toBeInstanceOf(Error)
|
|
expect(errorArg.message).toBe('Queue job error')
|
|
expect(optionsArg).toEqual({ reportType: 'queueJobError' })
|
|
})
|
|
|
|
it('does nothing when no error message exists', () => {
|
|
taskState.value = createTaskWithError()
|
|
composable.reportJobError()
|
|
expect(showErrorDialog).not.toHaveBeenCalled()
|
|
})
|
|
})
|