mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-09 01:20:09 +00:00
simplify widget registration
This commit is contained in:
@@ -50,10 +50,10 @@ import { LODLevel } from '@/renderer/extensions/vueNodes/lod/useLOD'
|
||||
// Import widget components directly
|
||||
import WidgetInputText from '@/renderer/extensions/vueNodes/widgets/components/WidgetInputText.vue'
|
||||
import {
|
||||
ESSENTIAL_WIDGET_TYPES,
|
||||
useWidgetRenderer
|
||||
} from '@/renderer/extensions/vueNodes/widgets/composables/useWidgetRenderer'
|
||||
import { widgetTypeToComponent } from '@/renderer/extensions/vueNodes/widgets/registry/widgetRegistry'
|
||||
getComponent,
|
||||
isEssential,
|
||||
shouldRenderAsVue
|
||||
} from '@/renderer/extensions/vueNodes/widgets/registry/widgetRegistry'
|
||||
import type { SimplifiedWidget, WidgetValue } from '@/types/simplifiedWidget'
|
||||
|
||||
import InputSlot from './InputSlot.vue'
|
||||
@@ -67,9 +67,6 @@ interface NodeWidgetsProps {
|
||||
|
||||
const props = defineProps<NodeWidgetsProps>()
|
||||
|
||||
// Use widget renderer composable
|
||||
const { getWidgetComponent, shouldRenderAsVue } = useWidgetRenderer()
|
||||
|
||||
// Error boundary implementation
|
||||
const renderError = ref<string | null>(null)
|
||||
|
||||
@@ -110,14 +107,9 @@ const processedWidgets = computed((): ProcessedWidget[] => {
|
||||
if (!widget.type) continue
|
||||
if (!shouldRenderAsVue(widget)) continue
|
||||
|
||||
if (
|
||||
lodLevel === LODLevel.REDUCED &&
|
||||
!ESSENTIAL_WIDGET_TYPES.has(widget.type)
|
||||
)
|
||||
continue
|
||||
if (lodLevel === LODLevel.REDUCED && !isEssential(widget.type)) continue
|
||||
|
||||
const componentName = getWidgetComponent(widget.type)
|
||||
const vueComponent = widgetTypeToComponent[componentName] || WidgetInputText
|
||||
const vueComponent = getComponent(widget.type) || WidgetInputText
|
||||
|
||||
const simplified: SimplifiedWidget = {
|
||||
name: widget.name,
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
/**
|
||||
* Widget renderer composable for Vue node system
|
||||
* Maps LiteGraph widget types to Vue components
|
||||
*/
|
||||
import { WidgetType, widgetTypeToComponent } from '../registry/widgetRegistry'
|
||||
|
||||
/**
|
||||
* Static mapping of LiteGraph widget types to Vue widget component names
|
||||
*/
|
||||
const TYPE_TO_ENUM_MAP: Record<string, string> = {
|
||||
// Number inputs
|
||||
number: WidgetType.NUMBER,
|
||||
slider: WidgetType.SLIDER,
|
||||
INT: WidgetType.INT,
|
||||
FLOAT: WidgetType.FLOAT,
|
||||
|
||||
// Text inputs
|
||||
text: WidgetType.STRING,
|
||||
string: WidgetType.STRING,
|
||||
STRING: WidgetType.STRING,
|
||||
|
||||
// Selection
|
||||
combo: WidgetType.COMBO,
|
||||
COMBO: WidgetType.COMBO,
|
||||
selectbutton: WidgetType.SELECTBUTTON,
|
||||
SELECTBUTTON: WidgetType.SELECTBUTTON,
|
||||
multiselect: WidgetType.MULTISELECT,
|
||||
MULTISELECT: WidgetType.MULTISELECT,
|
||||
treeselect: WidgetType.TREESELECT,
|
||||
TREESELECT: WidgetType.TREESELECT,
|
||||
|
||||
// Boolean
|
||||
toggle: WidgetType.TOGGLESWITCH,
|
||||
boolean: WidgetType.BOOLEAN,
|
||||
BOOLEAN: WidgetType.BOOLEAN,
|
||||
|
||||
// Multiline text
|
||||
multiline: WidgetType.TEXTAREA,
|
||||
textarea: WidgetType.TEXTAREA,
|
||||
TEXTAREA: WidgetType.TEXTAREA,
|
||||
customtext: WidgetType.TEXTAREA,
|
||||
MARKDOWN: WidgetType.MARKDOWN,
|
||||
|
||||
// Advanced widgets
|
||||
color: WidgetType.COLOR,
|
||||
COLOR: WidgetType.COLOR,
|
||||
imagecompare: WidgetType.IMAGECOMPARE,
|
||||
IMAGECOMPARE: WidgetType.IMAGECOMPARE,
|
||||
galleria: WidgetType.GALLERIA,
|
||||
GALLERIA: WidgetType.GALLERIA,
|
||||
file: WidgetType.FILEUPLOAD,
|
||||
fileupload: WidgetType.FILEUPLOAD,
|
||||
FILEUPLOAD: WidgetType.FILEUPLOAD,
|
||||
|
||||
// Button widget
|
||||
button: WidgetType.BUTTON,
|
||||
BUTTON: WidgetType.BUTTON,
|
||||
|
||||
// Chart widget
|
||||
chart: WidgetType.CHART,
|
||||
CHART: WidgetType.CHART
|
||||
} as const
|
||||
|
||||
/**
|
||||
* Pre-computed widget support map for O(1) lookups
|
||||
* Maps widget type directly to boolean for fast shouldRenderAsVue checks
|
||||
*/
|
||||
const WIDGET_SUPPORT_MAP = new Map(
|
||||
Object.entries(TYPE_TO_ENUM_MAP).map(([type, enumValue]) => [
|
||||
type,
|
||||
widgetTypeToComponent[enumValue] !== undefined
|
||||
])
|
||||
)
|
||||
|
||||
export const ESSENTIAL_WIDGET_TYPES = new Set([
|
||||
'combo',
|
||||
'COMBO',
|
||||
'select',
|
||||
'toggle',
|
||||
'boolean',
|
||||
'BOOLEAN',
|
||||
'slider',
|
||||
'number',
|
||||
'INT',
|
||||
'FLOAT'
|
||||
])
|
||||
|
||||
export const useWidgetRenderer = () => {
|
||||
const getWidgetComponent = (widgetType: string): string => {
|
||||
const enumKey = TYPE_TO_ENUM_MAP[widgetType]
|
||||
|
||||
if (enumKey && widgetTypeToComponent[enumKey]) {
|
||||
return enumKey
|
||||
}
|
||||
|
||||
return WidgetType.STRING
|
||||
}
|
||||
|
||||
const shouldRenderAsVue = (widget: {
|
||||
type?: string
|
||||
options?: Record<string, unknown>
|
||||
}): boolean => {
|
||||
if (widget.options?.canvasOnly) return false
|
||||
if (!widget.type) return false
|
||||
|
||||
// Check if widget type is explicitly supported
|
||||
const isSupported = WIDGET_SUPPORT_MAP.get(widget.type)
|
||||
if (isSupported !== undefined) return isSupported
|
||||
|
||||
// Fallback: unknown types are rendered as STRING widget
|
||||
return widgetTypeToComponent[WidgetType.STRING] !== undefined
|
||||
}
|
||||
|
||||
return {
|
||||
getWidgetComponent,
|
||||
shouldRenderAsVue
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@
|
||||
*/
|
||||
import type { Component } from 'vue'
|
||||
|
||||
// Component imports
|
||||
import WidgetButton from '../components/WidgetButton.vue'
|
||||
import WidgetChart from '../components/WidgetChart.vue'
|
||||
import WidgetColorPicker from '../components/WidgetColorPicker.vue'
|
||||
@@ -20,54 +19,132 @@ import WidgetTextarea from '../components/WidgetTextarea.vue'
|
||||
import WidgetToggleSwitch from '../components/WidgetToggleSwitch.vue'
|
||||
import WidgetTreeSelect from '../components/WidgetTreeSelect.vue'
|
||||
|
||||
/**
|
||||
* Enum of all available widget types
|
||||
*/
|
||||
export enum WidgetType {
|
||||
BUTTON = 'BUTTON',
|
||||
STRING = 'STRING',
|
||||
INT = 'INT',
|
||||
FLOAT = 'FLOAT',
|
||||
NUMBER = 'NUMBER',
|
||||
BOOLEAN = 'BOOLEAN',
|
||||
COMBO = 'COMBO',
|
||||
COLOR = 'COLOR',
|
||||
MULTISELECT = 'MULTISELECT',
|
||||
SELECTBUTTON = 'SELECTBUTTON',
|
||||
SLIDER = 'SLIDER',
|
||||
TEXTAREA = 'TEXTAREA',
|
||||
TOGGLESWITCH = 'TOGGLESWITCH',
|
||||
CHART = 'CHART',
|
||||
IMAGECOMPARE = 'IMAGECOMPARE',
|
||||
GALLERIA = 'GALLERIA',
|
||||
FILEUPLOAD = 'FILEUPLOAD',
|
||||
TREESELECT = 'TREESELECT',
|
||||
MARKDOWN = 'MARKDOWN'
|
||||
interface WidgetDefinition {
|
||||
component: Component
|
||||
aliases: string[]
|
||||
essential: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps widget types to their corresponding Vue components
|
||||
* Components will be added as they are implemented
|
||||
*/
|
||||
export const widgetTypeToComponent: Record<string, Component> = {
|
||||
// Components will be uncommented as they are implemented
|
||||
[WidgetType.BUTTON]: WidgetButton,
|
||||
[WidgetType.STRING]: WidgetInputText,
|
||||
[WidgetType.INT]: WidgetSlider,
|
||||
[WidgetType.FLOAT]: WidgetSlider,
|
||||
[WidgetType.NUMBER]: WidgetSlider, // For compatibility
|
||||
[WidgetType.BOOLEAN]: WidgetToggleSwitch,
|
||||
[WidgetType.COMBO]: WidgetSelect,
|
||||
[WidgetType.COLOR]: WidgetColorPicker,
|
||||
[WidgetType.MULTISELECT]: WidgetMultiSelect,
|
||||
[WidgetType.SELECTBUTTON]: WidgetSelectButton,
|
||||
[WidgetType.SLIDER]: WidgetSlider,
|
||||
[WidgetType.TEXTAREA]: WidgetTextarea,
|
||||
[WidgetType.TOGGLESWITCH]: WidgetToggleSwitch,
|
||||
[WidgetType.CHART]: WidgetChart,
|
||||
[WidgetType.IMAGECOMPARE]: WidgetImageCompare,
|
||||
[WidgetType.GALLERIA]: WidgetGalleria,
|
||||
[WidgetType.FILEUPLOAD]: WidgetFileUpload,
|
||||
[WidgetType.TREESELECT]: WidgetTreeSelect,
|
||||
[WidgetType.MARKDOWN]: WidgetMarkdown
|
||||
const coreWidgetDefinitions: Array<[string, WidgetDefinition]> = [
|
||||
[
|
||||
'button',
|
||||
{ component: WidgetButton, aliases: ['BUTTON'], essential: false }
|
||||
],
|
||||
[
|
||||
'string',
|
||||
{
|
||||
component: WidgetInputText,
|
||||
aliases: ['STRING', 'text'],
|
||||
essential: false
|
||||
}
|
||||
],
|
||||
['int', { component: WidgetSlider, aliases: ['INT'], essential: true }],
|
||||
[
|
||||
'float',
|
||||
{
|
||||
component: WidgetSlider,
|
||||
aliases: ['FLOAT', 'number', 'slider'],
|
||||
essential: true
|
||||
}
|
||||
],
|
||||
[
|
||||
'boolean',
|
||||
{
|
||||
component: WidgetToggleSwitch,
|
||||
aliases: ['BOOLEAN', 'toggle'],
|
||||
essential: true
|
||||
}
|
||||
],
|
||||
['combo', { component: WidgetSelect, aliases: ['COMBO'], essential: true }],
|
||||
[
|
||||
'color',
|
||||
{ component: WidgetColorPicker, aliases: ['COLOR'], essential: false }
|
||||
],
|
||||
[
|
||||
'multiselect',
|
||||
{ component: WidgetMultiSelect, aliases: ['MULTISELECT'], essential: false }
|
||||
],
|
||||
[
|
||||
'selectbutton',
|
||||
{
|
||||
component: WidgetSelectButton,
|
||||
aliases: ['SELECTBUTTON'],
|
||||
essential: false
|
||||
}
|
||||
],
|
||||
[
|
||||
'textarea',
|
||||
{
|
||||
component: WidgetTextarea,
|
||||
aliases: ['TEXTAREA', 'multiline', 'customtext'],
|
||||
essential: false
|
||||
}
|
||||
],
|
||||
['chart', { component: WidgetChart, aliases: ['CHART'], essential: false }],
|
||||
[
|
||||
'imagecompare',
|
||||
{
|
||||
component: WidgetImageCompare,
|
||||
aliases: ['IMAGECOMPARE'],
|
||||
essential: false
|
||||
}
|
||||
],
|
||||
[
|
||||
'galleria',
|
||||
{ component: WidgetGalleria, aliases: ['GALLERIA'], essential: false }
|
||||
],
|
||||
[
|
||||
'fileupload',
|
||||
{
|
||||
component: WidgetFileUpload,
|
||||
aliases: ['FILEUPLOAD', 'file'],
|
||||
essential: false
|
||||
}
|
||||
],
|
||||
[
|
||||
'treeselect',
|
||||
{ component: WidgetTreeSelect, aliases: ['TREESELECT'], essential: false }
|
||||
],
|
||||
[
|
||||
'markdown',
|
||||
{ component: WidgetMarkdown, aliases: ['MARKDOWN'], essential: false }
|
||||
]
|
||||
]
|
||||
|
||||
// Build lookup maps
|
||||
const widgets = new Map<string, WidgetDefinition>()
|
||||
const aliasMap = new Map<string, string>()
|
||||
|
||||
for (const [type, def] of coreWidgetDefinitions) {
|
||||
widgets.set(type, def)
|
||||
for (const alias of def.aliases) {
|
||||
aliasMap.set(alias, type)
|
||||
}
|
||||
}
|
||||
|
||||
// Utility functions
|
||||
const getCanonicalType = (type: string): string => aliasMap.get(type) || type
|
||||
|
||||
export const getComponent = (type: string): Component | null => {
|
||||
const canonicalType = getCanonicalType(type)
|
||||
return widgets.get(canonicalType)?.component || null
|
||||
}
|
||||
|
||||
export const isSupported = (type: string): boolean => {
|
||||
const canonicalType = getCanonicalType(type)
|
||||
return widgets.has(canonicalType)
|
||||
}
|
||||
|
||||
export const isEssential = (type: string): boolean => {
|
||||
const canonicalType = getCanonicalType(type)
|
||||
return widgets.get(canonicalType)?.essential || false
|
||||
}
|
||||
|
||||
export const shouldRenderAsVue = (widget: {
|
||||
type?: string
|
||||
options?: Record<string, unknown>
|
||||
}): boolean => {
|
||||
if (widget.options?.canvasOnly) return false
|
||||
if (!widget.type) return false
|
||||
return isSupported(widget.type)
|
||||
}
|
||||
|
||||
@@ -1,93 +1,100 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import { useWidgetRenderer } from '@/renderer/extensions/vueNodes/widgets/composables/useWidgetRenderer'
|
||||
import { WidgetType } from '@/renderer/extensions/vueNodes/widgets/registry/widgetRegistry'
|
||||
import WidgetButton from '@/renderer/extensions/vueNodes/widgets/components/WidgetButton.vue'
|
||||
import WidgetColorPicker from '@/renderer/extensions/vueNodes/widgets/components/WidgetColorPicker.vue'
|
||||
import WidgetFileUpload from '@/renderer/extensions/vueNodes/widgets/components/WidgetFileUpload.vue'
|
||||
import WidgetInputText from '@/renderer/extensions/vueNodes/widgets/components/WidgetInputText.vue'
|
||||
import WidgetMarkdown from '@/renderer/extensions/vueNodes/widgets/components/WidgetMarkdown.vue'
|
||||
import WidgetSelect from '@/renderer/extensions/vueNodes/widgets/components/WidgetSelect.vue'
|
||||
import WidgetSlider from '@/renderer/extensions/vueNodes/widgets/components/WidgetSlider.vue'
|
||||
import WidgetTextarea from '@/renderer/extensions/vueNodes/widgets/components/WidgetTextarea.vue'
|
||||
import WidgetToggleSwitch from '@/renderer/extensions/vueNodes/widgets/components/WidgetToggleSwitch.vue'
|
||||
import {
|
||||
getComponent,
|
||||
isEssential,
|
||||
shouldRenderAsVue
|
||||
} from '@/renderer/extensions/vueNodes/widgets/registry/widgetRegistry'
|
||||
|
||||
describe('useWidgetRenderer', () => {
|
||||
const { getWidgetComponent, shouldRenderAsVue } = useWidgetRenderer()
|
||||
|
||||
describe('getWidgetComponent', () => {
|
||||
describe('widgetRegistry', () => {
|
||||
describe('getComponent', () => {
|
||||
// Test number type mappings
|
||||
describe('number types', () => {
|
||||
it('should map number type to NUMBER widget', () => {
|
||||
expect(getWidgetComponent('number')).toBe(WidgetType.NUMBER)
|
||||
it('should map int types to slider widget', () => {
|
||||
expect(getComponent('int')).toBe(WidgetSlider)
|
||||
expect(getComponent('INT')).toBe(WidgetSlider)
|
||||
})
|
||||
|
||||
it('should map slider type to SLIDER widget', () => {
|
||||
expect(getWidgetComponent('slider')).toBe(WidgetType.SLIDER)
|
||||
})
|
||||
|
||||
it('should map INT type to INT widget', () => {
|
||||
expect(getWidgetComponent('INT')).toBe(WidgetType.INT)
|
||||
})
|
||||
|
||||
it('should map FLOAT type to FLOAT widget', () => {
|
||||
expect(getWidgetComponent('FLOAT')).toBe(WidgetType.FLOAT)
|
||||
it('should map float types to slider widget', () => {
|
||||
expect(getComponent('float')).toBe(WidgetSlider)
|
||||
expect(getComponent('FLOAT')).toBe(WidgetSlider)
|
||||
expect(getComponent('number')).toBe(WidgetSlider)
|
||||
expect(getComponent('slider')).toBe(WidgetSlider)
|
||||
})
|
||||
})
|
||||
|
||||
// Test text type mappings
|
||||
describe('text types', () => {
|
||||
it('should map text variations to STRING widget', () => {
|
||||
expect(getWidgetComponent('text')).toBe(WidgetType.STRING)
|
||||
expect(getWidgetComponent('string')).toBe(WidgetType.STRING)
|
||||
expect(getWidgetComponent('STRING')).toBe(WidgetType.STRING)
|
||||
it('should map text variations to input text widget', () => {
|
||||
expect(getComponent('text')).toBe(WidgetInputText)
|
||||
expect(getComponent('string')).toBe(WidgetInputText)
|
||||
expect(getComponent('STRING')).toBe(WidgetInputText)
|
||||
})
|
||||
|
||||
it('should map multiline text types to TEXTAREA widget', () => {
|
||||
expect(getWidgetComponent('multiline')).toBe(WidgetType.TEXTAREA)
|
||||
expect(getWidgetComponent('textarea')).toBe(WidgetType.TEXTAREA)
|
||||
expect(getWidgetComponent('MARKDOWN')).toBe(WidgetType.MARKDOWN)
|
||||
expect(getWidgetComponent('customtext')).toBe(WidgetType.TEXTAREA)
|
||||
it('should map multiline text types to textarea widget', () => {
|
||||
expect(getComponent('multiline')).toBe(WidgetTextarea)
|
||||
expect(getComponent('textarea')).toBe(WidgetTextarea)
|
||||
expect(getComponent('TEXTAREA')).toBe(WidgetTextarea)
|
||||
expect(getComponent('customtext')).toBe(WidgetTextarea)
|
||||
})
|
||||
|
||||
it('should map markdown to markdown widget', () => {
|
||||
expect(getComponent('MARKDOWN')).toBe(WidgetMarkdown)
|
||||
expect(getComponent('markdown')).toBe(WidgetMarkdown)
|
||||
})
|
||||
})
|
||||
|
||||
// Test selection type mappings
|
||||
describe('selection types', () => {
|
||||
it('should map combo types to COMBO widget', () => {
|
||||
expect(getWidgetComponent('combo')).toBe(WidgetType.COMBO)
|
||||
expect(getWidgetComponent('COMBO')).toBe(WidgetType.COMBO)
|
||||
it('should map combo types to select widget', () => {
|
||||
expect(getComponent('combo')).toBe(WidgetSelect)
|
||||
expect(getComponent('COMBO')).toBe(WidgetSelect)
|
||||
})
|
||||
})
|
||||
|
||||
// Test boolean type mappings
|
||||
describe('boolean types', () => {
|
||||
it('should map boolean types to appropriate widgets', () => {
|
||||
expect(getWidgetComponent('toggle')).toBe(WidgetType.TOGGLESWITCH)
|
||||
expect(getWidgetComponent('boolean')).toBe(WidgetType.BOOLEAN)
|
||||
expect(getWidgetComponent('BOOLEAN')).toBe(WidgetType.BOOLEAN)
|
||||
it('should map boolean types to toggle switch widget', () => {
|
||||
expect(getComponent('toggle')).toBe(WidgetToggleSwitch)
|
||||
expect(getComponent('boolean')).toBe(WidgetToggleSwitch)
|
||||
expect(getComponent('BOOLEAN')).toBe(WidgetToggleSwitch)
|
||||
})
|
||||
})
|
||||
|
||||
// Test advanced widget mappings
|
||||
describe('advanced widgets', () => {
|
||||
it('should map color types to COLOR widget', () => {
|
||||
expect(getWidgetComponent('color')).toBe(WidgetType.COLOR)
|
||||
expect(getWidgetComponent('COLOR')).toBe(WidgetType.COLOR)
|
||||
it('should map color types to color picker widget', () => {
|
||||
expect(getComponent('color')).toBe(WidgetColorPicker)
|
||||
expect(getComponent('COLOR')).toBe(WidgetColorPicker)
|
||||
})
|
||||
|
||||
it('should map file types to FILEUPLOAD widget', () => {
|
||||
expect(getWidgetComponent('file')).toBe(WidgetType.FILEUPLOAD)
|
||||
expect(getWidgetComponent('FILEUPLOAD')).toBe(WidgetType.FILEUPLOAD)
|
||||
it('should map file types to file upload widget', () => {
|
||||
expect(getComponent('file')).toBe(WidgetFileUpload)
|
||||
expect(getComponent('fileupload')).toBe(WidgetFileUpload)
|
||||
expect(getComponent('FILEUPLOAD')).toBe(WidgetFileUpload)
|
||||
})
|
||||
|
||||
it('should map button types to BUTTON widget', () => {
|
||||
expect(getWidgetComponent('button')).toBe(WidgetType.BUTTON)
|
||||
expect(getWidgetComponent('BUTTON')).toBe(WidgetType.BUTTON)
|
||||
it('should map button types to button widget', () => {
|
||||
expect(getComponent('button')).toBe(WidgetButton)
|
||||
expect(getComponent('BUTTON')).toBe(WidgetButton)
|
||||
})
|
||||
})
|
||||
|
||||
// Test fallback behavior
|
||||
describe('fallback behavior', () => {
|
||||
it('should return STRING widget for unknown types', () => {
|
||||
expect(getWidgetComponent('unknown')).toBe(WidgetType.STRING)
|
||||
expect(getWidgetComponent('custom_widget')).toBe(WidgetType.STRING)
|
||||
expect(getWidgetComponent('')).toBe(WidgetType.STRING)
|
||||
})
|
||||
|
||||
it('should return STRING widget for unmapped but valid types', () => {
|
||||
expect(getWidgetComponent('datetime')).toBe(WidgetType.STRING)
|
||||
expect(getWidgetComponent('json')).toBe(WidgetType.STRING)
|
||||
it('should return null for unknown types', () => {
|
||||
expect(getComponent('unknown')).toBe(null)
|
||||
expect(getComponent('custom_widget')).toBe(null)
|
||||
expect(getComponent('')).toBe(null)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -105,12 +112,12 @@ describe('useWidgetRenderer', () => {
|
||||
|
||||
it('should return true for widgets with mapped types', () => {
|
||||
expect(shouldRenderAsVue({ type: 'text' })).toBe(true)
|
||||
expect(shouldRenderAsVue({ type: 'number' })).toBe(true)
|
||||
expect(shouldRenderAsVue({ type: 'int' })).toBe(true)
|
||||
expect(shouldRenderAsVue({ type: 'combo' })).toBe(true)
|
||||
})
|
||||
|
||||
it('should return true even for unknown types (fallback to STRING)', () => {
|
||||
expect(shouldRenderAsVue({ type: 'unknown_type' })).toBe(true)
|
||||
it('should return false for unknown types', () => {
|
||||
expect(shouldRenderAsVue({ type: 'unknown_type' })).toBe(false)
|
||||
})
|
||||
|
||||
it('should respect options while checking type', () => {
|
||||
@@ -119,18 +126,43 @@ describe('useWidgetRenderer', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('isEssential', () => {
|
||||
it('should identify essential widget types', () => {
|
||||
expect(isEssential('int')).toBe(true)
|
||||
expect(isEssential('INT')).toBe(true)
|
||||
expect(isEssential('float')).toBe(true)
|
||||
expect(isEssential('FLOAT')).toBe(true)
|
||||
expect(isEssential('boolean')).toBe(true)
|
||||
expect(isEssential('BOOLEAN')).toBe(true)
|
||||
expect(isEssential('combo')).toBe(true)
|
||||
expect(isEssential('COMBO')).toBe(true)
|
||||
})
|
||||
|
||||
it('should identify non-essential widget types', () => {
|
||||
expect(isEssential('button')).toBe(false)
|
||||
expect(isEssential('color')).toBe(false)
|
||||
expect(isEssential('chart')).toBe(false)
|
||||
expect(isEssential('fileupload')).toBe(false)
|
||||
})
|
||||
|
||||
it('should return false for unknown types', () => {
|
||||
expect(isEssential('unknown')).toBe(false)
|
||||
expect(isEssential('')).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('edge cases', () => {
|
||||
it('should handle widgets with empty options', () => {
|
||||
const widget = { type: 'text', options: {} }
|
||||
expect(shouldRenderAsVue(widget)).toBe(true)
|
||||
})
|
||||
|
||||
it('should handle case sensitivity correctly', () => {
|
||||
it('should handle case sensitivity correctly through aliases', () => {
|
||||
// Test that both lowercase and uppercase work
|
||||
expect(getWidgetComponent('string')).toBe(WidgetType.STRING)
|
||||
expect(getWidgetComponent('STRING')).toBe(WidgetType.STRING)
|
||||
expect(getWidgetComponent('combo')).toBe(WidgetType.COMBO)
|
||||
expect(getWidgetComponent('COMBO')).toBe(WidgetType.COMBO)
|
||||
expect(getComponent('string')).toBe(WidgetInputText)
|
||||
expect(getComponent('STRING')).toBe(WidgetInputText)
|
||||
expect(getComponent('combo')).toBe(WidgetSelect)
|
||||
expect(getComponent('COMBO')).toBe(WidgetSelect)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user