mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-27 17:52:16 +00:00
Add Vue Combo (dropdown) widget (#4113)
This commit is contained in:
109
tests-ui/tests/composables/useDropdownComboWidget.test.ts
Normal file
109
tests-ui/tests/composables/useDropdownComboWidget.test.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
import type { LGraphNode } from '@comfyorg/litegraph'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import { useDropdownComboWidget } from '@/composables/widgets/useDropdownComboWidget'
|
||||
import type { ComboInputSpec } from '@/schemas/nodeDef/nodeDefSchemaV2'
|
||||
|
||||
// Mock the domWidget store and related dependencies
|
||||
vi.mock('@/scripts/domWidget', () => ({
|
||||
ComponentWidgetImpl: vi.fn().mockImplementation((config) => ({
|
||||
name: config.name,
|
||||
value: '',
|
||||
options: config.options
|
||||
})),
|
||||
addWidget: vi.fn()
|
||||
}))
|
||||
|
||||
// Mock the scripts/widgets for control widgets
|
||||
vi.mock('@/scripts/widgets', () => ({
|
||||
addValueControlWidgets: vi.fn().mockReturnValue([])
|
||||
}))
|
||||
|
||||
// Mock the remote widget functionality
|
||||
vi.mock('@/composables/widgets/useRemoteWidget', () => ({
|
||||
useRemoteWidget: vi.fn(() => ({
|
||||
addRefreshButton: vi.fn()
|
||||
}))
|
||||
}))
|
||||
|
||||
const createMockNode = () => {
|
||||
return {
|
||||
widgets: [],
|
||||
graph: {
|
||||
setDirtyCanvas: vi.fn()
|
||||
},
|
||||
addWidget: vi.fn(),
|
||||
addCustomWidget: vi.fn(),
|
||||
setDirtyCanvas: vi.fn()
|
||||
} as unknown as LGraphNode
|
||||
}
|
||||
|
||||
describe('useDropdownComboWidget', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
it('creates widget constructor successfully', () => {
|
||||
const constructor = useDropdownComboWidget()
|
||||
expect(constructor).toBeDefined()
|
||||
expect(typeof constructor).toBe('function')
|
||||
})
|
||||
|
||||
it('widget constructor handles input spec correctly', () => {
|
||||
const constructor = useDropdownComboWidget()
|
||||
const mockNode = createMockNode()
|
||||
|
||||
const inputSpec: ComboInputSpec = {
|
||||
name: 'test_dropdown',
|
||||
type: 'COMBO',
|
||||
options: ['option1', 'option2', 'option3']
|
||||
}
|
||||
|
||||
const widget = constructor(mockNode, inputSpec)
|
||||
|
||||
expect(widget).toBeDefined()
|
||||
expect(widget.name).toBe('test_dropdown')
|
||||
})
|
||||
|
||||
it('widget constructor accepts default value option', () => {
|
||||
const constructor = useDropdownComboWidget({ defaultValue: 'custom' })
|
||||
expect(constructor).toBeDefined()
|
||||
expect(typeof constructor).toBe('function')
|
||||
})
|
||||
|
||||
it('handles remote widgets correctly', () => {
|
||||
const constructor = useDropdownComboWidget()
|
||||
const mockNode = createMockNode()
|
||||
|
||||
const inputSpec: ComboInputSpec = {
|
||||
name: 'remote_dropdown',
|
||||
type: 'COMBO',
|
||||
options: [],
|
||||
remote: {
|
||||
route: '/api/options',
|
||||
refresh_button: true
|
||||
}
|
||||
}
|
||||
|
||||
const widget = constructor(mockNode, inputSpec)
|
||||
|
||||
expect(widget).toBeDefined()
|
||||
expect(widget.name).toBe('remote_dropdown')
|
||||
})
|
||||
|
||||
it('handles control_after_generate widgets correctly', () => {
|
||||
const constructor = useDropdownComboWidget()
|
||||
const mockNode = createMockNode()
|
||||
|
||||
const inputSpec: ComboInputSpec = {
|
||||
name: 'control_dropdown',
|
||||
type: 'COMBO',
|
||||
options: ['option1', 'option2'],
|
||||
control_after_generate: true
|
||||
}
|
||||
|
||||
const widget = constructor(mockNode, inputSpec)
|
||||
|
||||
expect(widget).toBeDefined()
|
||||
expect(widget.name).toBe('control_dropdown')
|
||||
})
|
||||
})
|
||||
@@ -1,39 +1,89 @@
|
||||
import type { LGraphNode } from '@comfyorg/litegraph'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import { useComboWidget } from '@/composables/widgets/useComboWidget'
|
||||
import type { InputSpec } from '@/schemas/nodeDef/nodeDefSchemaV2'
|
||||
import type { ComboInputSpec } from '@/schemas/nodeDef/nodeDefSchemaV2'
|
||||
|
||||
vi.mock('@/scripts/widgets', () => ({
|
||||
addValueControlWidgets: vi.fn()
|
||||
// Mock the dropdown combo widget since COMBO now uses it
|
||||
vi.mock('@/composables/widgets/useDropdownComboWidget', () => ({
|
||||
useDropdownComboWidget: vi.fn(() =>
|
||||
vi.fn().mockReturnValue({ name: 'mockWidget' })
|
||||
)
|
||||
}))
|
||||
|
||||
// Mock the domWidget store and related dependencies
|
||||
vi.mock('@/scripts/domWidget', () => ({
|
||||
ComponentWidgetImpl: vi.fn().mockImplementation((config) => ({
|
||||
name: config.name,
|
||||
value: [],
|
||||
options: config.options
|
||||
})),
|
||||
addWidget: vi.fn()
|
||||
}))
|
||||
|
||||
const createMockNode = () => {
|
||||
return {
|
||||
widgets: [],
|
||||
graph: {
|
||||
setDirtyCanvas: vi.fn()
|
||||
},
|
||||
addWidget: vi.fn(),
|
||||
addCustomWidget: vi.fn(),
|
||||
setDirtyCanvas: vi.fn()
|
||||
} as unknown as LGraphNode
|
||||
}
|
||||
|
||||
describe('useComboWidget', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
it('should handle undefined spec', () => {
|
||||
it('should delegate single-selection combo to dropdown widget', () => {
|
||||
const constructor = useComboWidget()
|
||||
const mockNode = {
|
||||
addWidget: vi.fn().mockReturnValue({ options: {} } as any)
|
||||
}
|
||||
const mockNode = createMockNode()
|
||||
|
||||
const inputSpec: InputSpec = {
|
||||
const inputSpec: ComboInputSpec = {
|
||||
type: 'COMBO',
|
||||
name: 'inputName'
|
||||
name: 'inputName',
|
||||
options: ['option1', 'option2']
|
||||
}
|
||||
|
||||
const widget = constructor(mockNode as any, inputSpec)
|
||||
const widget = constructor(mockNode, inputSpec)
|
||||
|
||||
expect(mockNode.addWidget).toHaveBeenCalledWith(
|
||||
'combo',
|
||||
'inputName',
|
||||
undefined, // default value
|
||||
expect.any(Function), // callback
|
||||
expect.objectContaining({
|
||||
values: []
|
||||
})
|
||||
// Should create a widget (delegated to dropdown widget)
|
||||
expect(widget).toBeDefined()
|
||||
expect(widget.name).toBe('mockWidget')
|
||||
})
|
||||
|
||||
it('should use multi-select widget for multi_select combo', () => {
|
||||
const constructor = useComboWidget()
|
||||
const mockNode = createMockNode()
|
||||
|
||||
const inputSpec: ComboInputSpec = {
|
||||
type: 'COMBO',
|
||||
name: 'multiSelectInput',
|
||||
options: ['option1', 'option2'],
|
||||
multi_select: { placeholder: 'Select multiple' }
|
||||
}
|
||||
|
||||
const widget = constructor(mockNode, inputSpec)
|
||||
|
||||
// Should create a multi-select widget
|
||||
expect(widget).toBeDefined()
|
||||
expect(widget.name).toBe('multiSelectInput')
|
||||
})
|
||||
|
||||
it('should handle invalid input spec', () => {
|
||||
const constructor = useComboWidget()
|
||||
const mockNode = createMockNode()
|
||||
|
||||
const invalidSpec = {
|
||||
type: 'NOT_COMBO',
|
||||
name: 'invalidInput'
|
||||
} as any
|
||||
|
||||
expect(() => constructor(mockNode, invalidSpec)).toThrow(
|
||||
'Invalid input data'
|
||||
)
|
||||
expect(widget).toEqual({ options: {} })
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user