Files
ComfyUI_frontend/tests-ui/tests/utils/nodeDefUtil.test.ts
2025-03-18 22:57:17 -04:00

224 lines
7.5 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import type {
ComboInputSpec,
ComboInputSpecV2,
FloatInputSpec,
InputSpec,
IntInputSpec
} from '@/schemas/nodeDefSchema'
import { mergeInputSpec } from '@/utils/nodeDefUtil'
describe('nodeDefUtil', () => {
describe('mergeInputSpec', () => {
// Test numeric input specs (INT and FLOAT)
describe('numeric input specs', () => {
it('should merge INT specs with overlapping ranges', () => {
const spec1: IntInputSpec = ['INT', { min: 0, max: 10 }]
const spec2: IntInputSpec = ['INT', { min: 5, max: 15 }]
const result = mergeInputSpec(spec1, spec2)
expect(result).not.toBeNull()
expect(result?.[0]).toBe('INT')
// @ts-expect-error fixme ts strict error
expect(result?.[1].min).toBe(5)
// @ts-expect-error fixme ts strict error
expect(result?.[1].max).toBe(10)
})
it('should return null for INT specs with non-overlapping ranges', () => {
const spec1: IntInputSpec = ['INT', { min: 0, max: 5 }]
const spec2: IntInputSpec = ['INT', { min: 10, max: 15 }]
const result = mergeInputSpec(spec1, spec2)
expect(result).toBeNull()
})
it('should merge FLOAT specs with overlapping ranges', () => {
const spec1: FloatInputSpec = ['FLOAT', { min: 0.5, max: 10.5 }]
const spec2: FloatInputSpec = ['FLOAT', { min: 5.5, max: 15.5 }]
const result = mergeInputSpec(spec1, spec2)
expect(result).not.toBeNull()
expect(result?.[0]).toBe('FLOAT')
// @ts-expect-error fixme ts strict error
expect(result?.[1].min).toBe(5.5)
// @ts-expect-error fixme ts strict error
expect(result?.[1].max).toBe(10.5)
})
it('should handle specs with undefined min/max values', () => {
const spec1: FloatInputSpec = ['FLOAT', { min: 0.5 }]
const spec2: FloatInputSpec = ['FLOAT', { max: 15.5 }]
const result = mergeInputSpec(spec1, spec2)
expect(result).not.toBeNull()
expect(result?.[0]).toBe('FLOAT')
// @ts-expect-error fixme ts strict error
expect(result?.[1].min).toBe(0.5)
// @ts-expect-error fixme ts strict error
expect(result?.[1].max).toBe(15.5)
})
it('should merge step values using least common multiple', () => {
const spec1: IntInputSpec = ['INT', { min: 0, max: 10, step: 2 }]
const spec2: IntInputSpec = ['INT', { min: 0, max: 10, step: 3 }]
const result = mergeInputSpec(spec1, spec2)
expect(result).not.toBeNull()
expect(result?.[0]).toBe('INT')
// @ts-expect-error fixme ts strict error
expect(result?.[1].step).toBe(6) // LCM of 2 and 3 is 6
})
it('should use default step of 1 when step is not specified', () => {
const spec1: IntInputSpec = ['INT', { min: 0, max: 10 }]
const spec2: IntInputSpec = ['INT', { min: 0, max: 10, step: 4 }]
const result = mergeInputSpec(spec1, spec2)
expect(result).not.toBeNull()
expect(result?.[0]).toBe('INT')
// @ts-expect-error fixme ts strict error
expect(result?.[1].step).toBe(4) // LCM of 1 and 4 is 4
})
it('should handle step values for FLOAT specs', () => {
const spec1: FloatInputSpec = ['FLOAT', { min: 0, max: 10, step: 0.5 }]
const spec2: FloatInputSpec = ['FLOAT', { min: 0, max: 10, step: 0.25 }]
const result = mergeInputSpec(spec1, spec2)
expect(result).not.toBeNull()
expect(result?.[0]).toBe('FLOAT')
// @ts-expect-error fixme ts strict error
expect(result?.[1].step).toBe(0.5)
})
})
// Test combo input specs
describe('combo input specs', () => {
it('should merge COMBO specs with overlapping options', () => {
const spec1: ComboInputSpecV2 = ['COMBO', { options: ['A', 'B', 'C'] }]
const spec2: ComboInputSpecV2 = ['COMBO', { options: ['B', 'C', 'D'] }]
const result = mergeInputSpec(spec1, spec2)
expect(result).not.toBeNull()
expect(result?.[0]).toBe('COMBO')
// @ts-expect-error fixme ts strict error
expect(result?.[1].options).toEqual(['B', 'C'])
})
it('should return null for COMBO specs with no overlapping options', () => {
const spec1: ComboInputSpecV2 = ['COMBO', { options: ['A', 'B'] }]
const spec2: ComboInputSpecV2 = ['COMBO', { options: ['C', 'D'] }]
const result = mergeInputSpec(spec1, spec2)
expect(result).toBeNull()
})
it('should handle COMBO specs with additional properties', () => {
const spec1: ComboInputSpecV2 = [
'COMBO',
{
options: ['A', 'B', 'C'],
default: 'A',
tooltip: 'Select an option'
}
]
const spec2: ComboInputSpecV2 = [
'COMBO',
{
options: ['B', 'C', 'D'],
default: 'B',
multiline: true
}
]
const result = mergeInputSpec(spec1, spec2)
expect(result).not.toBeNull()
expect(result?.[0]).toBe('COMBO')
// @ts-expect-error fixme ts strict error
expect(result?.[1].options).toEqual(['B', 'C'])
// @ts-expect-error fixme ts strict error
expect(result?.[1].default).toBe('B')
// @ts-expect-error fixme ts strict error
expect(result?.[1].tooltip).toBe('Select an option')
// @ts-expect-error fixme ts strict error
expect(result?.[1].multiline).toBe(true)
})
it('should handle v1 and v2 combo specs', () => {
const spec1: ComboInputSpec = [['A', 'B', 'C', 'D'], {}]
const spec2: ComboInputSpecV2 = ['COMBO', { options: ['C', 'D'] }]
const result = mergeInputSpec(spec1, spec2)
expect(result).not.toBeNull()
expect(result?.[0]).toBe('COMBO')
// @ts-expect-error fixme ts strict error
expect(result?.[1].options).toEqual(['C', 'D'])
})
})
// Test common input spec behavior
describe('common input spec behavior', () => {
it('should return null for specs with different types', () => {
const spec1: IntInputSpec = ['INT', { min: 0, max: 10 }]
const spec2: ComboInputSpecV2 = ['COMBO', { options: ['A', 'B'] }]
const result = mergeInputSpec(spec1, spec2 as unknown as IntInputSpec)
expect(result).toBeNull()
})
it('should ignore specified keys when comparing specs', () => {
const spec1: InputSpec = [
'STRING',
{
default: 'value1',
tooltip: 'Tooltip 1',
step: 1
}
]
const spec2: InputSpec = [
'STRING',
{
default: 'value2',
tooltip: 'Tooltip 2',
step: 1
}
]
const result = mergeInputSpec(spec1, spec2)
expect(result).not.toBeNull()
expect(result?.[0]).toBe('STRING')
// @ts-expect-error fixme ts strict error
expect(result?.[1].default).toBe('value2')
// @ts-expect-error fixme ts strict error
expect(result?.[1].tooltip).toBe('Tooltip 2')
// @ts-expect-error fixme ts strict error
expect(result?.[1].step).toBe(1)
})
it('should return null if non-ignored properties differ', () => {
const spec1: InputSpec = ['STRING', { step: 1 }]
const spec2: InputSpec = ['STRING', { step: 2 }]
const result = mergeInputSpec(spec1, spec2)
expect(result).toBeNull()
})
})
})
})