mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-09 17:40:09 +00:00
[Schema] ComfyNodeDefV2 schema (#2847)
This commit is contained in:
@@ -1,18 +1,12 @@
|
||||
// @ts-strict-ignore
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import type { ComfyNodeDef } from '@/schemas/nodeDefSchema'
|
||||
import {
|
||||
BooleanInputSpec,
|
||||
ComfyInputsSpec,
|
||||
ComfyNodeDefImpl,
|
||||
FloatInputSpec,
|
||||
IntInputSpec,
|
||||
StringInputSpec
|
||||
} from '@/stores/nodeDefStore'
|
||||
import { transformNodeDefV1ToV2 } from '@/schemas/nodeDef/migration'
|
||||
import type { ComfyNodeDef as ComfyNodeDefV1 } from '@/schemas/nodeDefSchema'
|
||||
import { ComfyNodeDefImpl } from '@/stores/nodeDefStore'
|
||||
|
||||
describe('ComfyInputsSpec', () => {
|
||||
it('should transform a plain object to ComfyInputsSpec instance', () => {
|
||||
describe('NodeDef Migration', () => {
|
||||
it('should transform a plain object to V2 format', () => {
|
||||
const plainObject = {
|
||||
required: {
|
||||
intInput: ['INT', { min: 0, max: 100, default: 50 }],
|
||||
@@ -28,13 +22,26 @@ describe('ComfyInputsSpec', () => {
|
||||
hidden: {
|
||||
someHiddenValue: 42
|
||||
}
|
||||
} as ComfyNodeDef['input']
|
||||
} as ComfyNodeDefV1['input']
|
||||
|
||||
const result = new ComfyInputsSpec(plainObject)
|
||||
const nodeDef: ComfyNodeDefV1 = {
|
||||
name: 'TestNode',
|
||||
display_name: 'Test Node',
|
||||
category: 'Testing',
|
||||
python_module: 'test_module',
|
||||
description: 'A test node',
|
||||
input: plainObject,
|
||||
output: ['INT'],
|
||||
output_is_list: [false],
|
||||
output_name: ['intOutput'],
|
||||
output_node: false
|
||||
}
|
||||
|
||||
expect(result).toBeInstanceOf(ComfyInputsSpec)
|
||||
expect(result.required).toBeDefined()
|
||||
expect(result.optional).toBeDefined()
|
||||
const result = transformNodeDefV1ToV2(nodeDef)
|
||||
|
||||
expect(result).toBeDefined()
|
||||
expect(result.inputs).toBeDefined()
|
||||
expect(result.outputs).toBeDefined()
|
||||
expect(result.hidden).toBeDefined()
|
||||
})
|
||||
|
||||
@@ -44,20 +51,35 @@ describe('ComfyInputsSpec', () => {
|
||||
intInput: ['INT', { min: 0, max: 100, default: 50 }],
|
||||
stringInput: ['STRING', { default: 'Hello', multiline: true }]
|
||||
}
|
||||
} as ComfyNodeDef['input']
|
||||
} as ComfyNodeDefV1['input']
|
||||
|
||||
const result = new ComfyInputsSpec(plainObject)
|
||||
const nodeDef: ComfyNodeDefV1 = {
|
||||
name: 'TestNode',
|
||||
display_name: 'Test Node',
|
||||
category: 'Testing',
|
||||
python_module: 'test_module',
|
||||
description: 'A test node',
|
||||
input: plainObject,
|
||||
output: [],
|
||||
output_is_list: [],
|
||||
output_name: [],
|
||||
output_node: false
|
||||
}
|
||||
|
||||
const intInput = result.required.intInput as IntInputSpec
|
||||
const stringInput = result.required.stringInput as StringInputSpec
|
||||
const result = transformNodeDefV1ToV2(nodeDef)
|
||||
|
||||
const intInput = result.inputs['intInput']
|
||||
const stringInput = result.inputs['stringInput']
|
||||
|
||||
expect(intInput.min).toBe(0)
|
||||
expect(intInput.max).toBe(100)
|
||||
expect(intInput.default).toBe(50)
|
||||
expect(intInput.name).toBe('intInput')
|
||||
expect(intInput.type).toBe('INT')
|
||||
expect(stringInput.default).toBe('Hello')
|
||||
expect(stringInput.multiline).toBe(true)
|
||||
expect(stringInput.name).toBe('stringInput')
|
||||
expect(stringInput.type).toBe('STRING')
|
||||
})
|
||||
|
||||
it('should correctly transform optional input specs', () => {
|
||||
@@ -69,19 +91,36 @@ describe('ComfyInputsSpec', () => {
|
||||
],
|
||||
floatInput: ['FLOAT', { min: 0, max: 1, step: 0.1 }]
|
||||
}
|
||||
} as ComfyNodeDef['input']
|
||||
} as ComfyNodeDefV1['input']
|
||||
|
||||
const result = new ComfyInputsSpec(plainObject)
|
||||
const nodeDef: ComfyNodeDefV1 = {
|
||||
name: 'TestNode',
|
||||
display_name: 'Test Node',
|
||||
category: 'Testing',
|
||||
python_module: 'test_module',
|
||||
description: 'A test node',
|
||||
input: plainObject,
|
||||
output: [],
|
||||
output_is_list: [],
|
||||
output_name: [],
|
||||
output_node: false
|
||||
}
|
||||
|
||||
const booleanInput = result.optional.booleanInput as BooleanInputSpec
|
||||
const floatInput = result.optional.floatInput as FloatInputSpec
|
||||
const result = transformNodeDefV1ToV2(nodeDef)
|
||||
|
||||
const booleanInput = result.inputs['booleanInput']
|
||||
const floatInput = result.inputs['floatInput']
|
||||
|
||||
expect(booleanInput.default).toBe(true)
|
||||
expect(booleanInput.labelOn).toBe('Yes')
|
||||
expect(booleanInput.labelOff).toBe('No')
|
||||
expect(booleanInput.type).toBe('BOOLEAN')
|
||||
expect(booleanInput.isOptional).toBe(true)
|
||||
expect(floatInput.min).toBe(0)
|
||||
expect(floatInput.max).toBe(1)
|
||||
expect(floatInput.step).toBe(0.1)
|
||||
expect(floatInput.type).toBe('FLOAT')
|
||||
expect(floatInput.isOptional).toBe(true)
|
||||
})
|
||||
|
||||
it('should handle combo input specs', () => {
|
||||
@@ -89,11 +128,25 @@ describe('ComfyInputsSpec', () => {
|
||||
optional: {
|
||||
comboInput: [[1, 2, 3], { default: 2 }]
|
||||
}
|
||||
} as ComfyNodeDef['input']
|
||||
} as ComfyNodeDefV1['input']
|
||||
|
||||
const result = new ComfyInputsSpec(plainObject)
|
||||
expect(result.optional.comboInput.type).toBe('COMBO')
|
||||
expect(result.optional.comboInput.default).toBe(2)
|
||||
const nodeDef: ComfyNodeDefV1 = {
|
||||
name: 'TestNode',
|
||||
display_name: 'Test Node',
|
||||
category: 'Testing',
|
||||
python_module: 'test_module',
|
||||
description: 'A test node',
|
||||
input: plainObject,
|
||||
output: [],
|
||||
output_is_list: [],
|
||||
output_name: [],
|
||||
output_node: false
|
||||
}
|
||||
|
||||
const result = transformNodeDefV1ToV2(nodeDef)
|
||||
expect(result.inputs['comboInput'].type).toBe('COMBO')
|
||||
expect(result.inputs['comboInput'].default).toBe(2)
|
||||
expect(result.inputs['comboInput'].options).toEqual([1, 2, 3])
|
||||
})
|
||||
|
||||
it('should handle combo input specs (auto-default)', () => {
|
||||
@@ -101,12 +154,25 @@ describe('ComfyInputsSpec', () => {
|
||||
optional: {
|
||||
comboInput: [[1, 2, 3], {}]
|
||||
}
|
||||
} as ComfyNodeDef['input']
|
||||
} as ComfyNodeDefV1['input']
|
||||
|
||||
const result = new ComfyInputsSpec(plainObject)
|
||||
expect(result.optional.comboInput.type).toBe('COMBO')
|
||||
const nodeDef: ComfyNodeDefV1 = {
|
||||
name: 'TestNode',
|
||||
display_name: 'Test Node',
|
||||
category: 'Testing',
|
||||
python_module: 'test_module',
|
||||
description: 'A test node',
|
||||
input: plainObject,
|
||||
output: [],
|
||||
output_is_list: [],
|
||||
output_name: [],
|
||||
output_node: false
|
||||
}
|
||||
|
||||
const result = transformNodeDefV1ToV2(nodeDef)
|
||||
expect(result.inputs['comboInput'].type).toBe('COMBO')
|
||||
// Should pick the first choice as default
|
||||
expect(result.optional.comboInput.default).toBe(1)
|
||||
expect(result.inputs['comboInput'].options).toEqual([1, 2, 3])
|
||||
})
|
||||
|
||||
it('should handle custom input specs', () => {
|
||||
@@ -114,11 +180,24 @@ describe('ComfyInputsSpec', () => {
|
||||
optional: {
|
||||
customInput: ['CUSTOM_TYPE', { default: 'custom value' }]
|
||||
}
|
||||
} as ComfyNodeDef['input']
|
||||
} as ComfyNodeDefV1['input']
|
||||
|
||||
const result = new ComfyInputsSpec(plainObject)
|
||||
expect(result.optional.customInput.type).toBe('CUSTOM_TYPE')
|
||||
expect(result.optional.customInput.default).toBe('custom value')
|
||||
const nodeDef: ComfyNodeDefV1 = {
|
||||
name: 'TestNode',
|
||||
display_name: 'Test Node',
|
||||
category: 'Testing',
|
||||
python_module: 'test_module',
|
||||
description: 'A test node',
|
||||
input: plainObject,
|
||||
output: [],
|
||||
output_is_list: [],
|
||||
output_name: [],
|
||||
output_node: false
|
||||
}
|
||||
|
||||
const result = transformNodeDefV1ToV2(nodeDef)
|
||||
expect(result.inputs['customInput'].type).toBe('CUSTOM_TYPE')
|
||||
expect(result.inputs['customInput'].default).toBe('custom value')
|
||||
})
|
||||
|
||||
it('should not transform hidden fields', () => {
|
||||
@@ -127,9 +206,22 @@ describe('ComfyInputsSpec', () => {
|
||||
someHiddenValue: 42,
|
||||
anotherHiddenValue: { nested: 'object' }
|
||||
}
|
||||
} as ComfyNodeDef['input']
|
||||
} as ComfyNodeDefV1['input']
|
||||
|
||||
const result = new ComfyInputsSpec(plainObject)
|
||||
const nodeDef: ComfyNodeDefV1 = {
|
||||
name: 'TestNode',
|
||||
display_name: 'Test Node',
|
||||
category: 'Testing',
|
||||
python_module: 'test_module',
|
||||
description: 'A test node',
|
||||
input: plainObject,
|
||||
output: [],
|
||||
output_is_list: [],
|
||||
output_name: [],
|
||||
output_node: false
|
||||
}
|
||||
|
||||
const result = transformNodeDefV1ToV2(nodeDef)
|
||||
|
||||
expect(result.hidden).toEqual(plainObject.hidden)
|
||||
expect(result.hidden?.someHiddenValue).toBe(42)
|
||||
@@ -139,11 +231,23 @@ describe('ComfyInputsSpec', () => {
|
||||
it('should handle empty or undefined fields', () => {
|
||||
const plainObject = {}
|
||||
|
||||
const result = new ComfyInputsSpec(plainObject)
|
||||
const nodeDef: ComfyNodeDefV1 = {
|
||||
name: 'TestNode',
|
||||
display_name: 'Test Node',
|
||||
category: 'Testing',
|
||||
python_module: 'test_module',
|
||||
description: 'A test node',
|
||||
input: plainObject,
|
||||
output: [],
|
||||
output_is_list: [],
|
||||
output_name: [],
|
||||
output_node: false
|
||||
}
|
||||
|
||||
expect(result).toBeInstanceOf(ComfyInputsSpec)
|
||||
expect(result.required).toEqual({})
|
||||
expect(result.optional).toEqual({})
|
||||
const result = transformNodeDefV1ToV2(nodeDef)
|
||||
|
||||
expect(result).toBeDefined()
|
||||
expect(result.inputs).toEqual({})
|
||||
expect(result.hidden).toBeUndefined()
|
||||
})
|
||||
})
|
||||
@@ -163,8 +267,9 @@ describe('ComfyNodeDefImpl', () => {
|
||||
},
|
||||
output: ['INT'],
|
||||
output_is_list: [false],
|
||||
output_name: ['intOutput']
|
||||
} as ComfyNodeDef
|
||||
output_name: ['intOutput'],
|
||||
output_node: false
|
||||
} as ComfyNodeDefV1
|
||||
|
||||
const result = new ComfyNodeDefImpl(plainObject)
|
||||
|
||||
@@ -174,8 +279,8 @@ describe('ComfyNodeDefImpl', () => {
|
||||
expect(result.category).toBe('Testing')
|
||||
expect(result.python_module).toBe('test_module')
|
||||
expect(result.description).toBe('A test node')
|
||||
expect(result.inputs).toBeInstanceOf(ComfyInputsSpec)
|
||||
expect(result.outputs.all).toEqual([
|
||||
expect(result.inputs).toBeDefined()
|
||||
expect(result.outputs).toEqual([
|
||||
{
|
||||
index: 0,
|
||||
name: 'intOutput',
|
||||
@@ -201,8 +306,9 @@ describe('ComfyNodeDefImpl', () => {
|
||||
output: ['INT'],
|
||||
output_is_list: [false],
|
||||
output_name: ['intOutput'],
|
||||
deprecated: true
|
||||
} as ComfyNodeDef
|
||||
deprecated: true,
|
||||
output_node: false
|
||||
} as ComfyNodeDefV1
|
||||
|
||||
const result = new ComfyNodeDefImpl(plainObject)
|
||||
expect(result.deprecated).toBe(true)
|
||||
@@ -224,8 +330,9 @@ describe('ComfyNodeDefImpl', () => {
|
||||
},
|
||||
output: ['INT'],
|
||||
output_is_list: [false],
|
||||
output_name: ['intOutput']
|
||||
} as ComfyNodeDef
|
||||
output_name: ['intOutput'],
|
||||
output_node: false
|
||||
} as ComfyNodeDefV1
|
||||
|
||||
const result = new ComfyNodeDefImpl(plainObject)
|
||||
expect(result.deprecated).toBe(true)
|
||||
@@ -241,12 +348,13 @@ describe('ComfyNodeDefImpl', () => {
|
||||
input: {},
|
||||
output: ['STRING', ['COMBO', 'option1', 'option2'], 'FLOAT'],
|
||||
output_is_list: [true, false, false],
|
||||
output_name: ['stringOutput', 'comboOutput', 'floatOutput']
|
||||
}
|
||||
output_name: ['stringOutput', 'comboOutput', 'floatOutput'],
|
||||
output_node: false
|
||||
} as ComfyNodeDefV1
|
||||
|
||||
const result = new ComfyNodeDefImpl(plainObject)
|
||||
|
||||
expect(result.outputs.all).toEqual([
|
||||
expect(result.outputs).toEqual([
|
||||
{
|
||||
index: 0,
|
||||
name: 'stringOutput',
|
||||
@@ -258,7 +366,7 @@ describe('ComfyNodeDefImpl', () => {
|
||||
name: 'comboOutput',
|
||||
type: 'COMBO',
|
||||
is_list: false,
|
||||
comboOptions: ['COMBO', 'option1', 'option2']
|
||||
options: ['COMBO', 'option1', 'option2']
|
||||
},
|
||||
{
|
||||
index: 2,
|
||||
@@ -279,12 +387,13 @@ describe('ComfyNodeDefImpl', () => {
|
||||
input: {},
|
||||
output: ['INT', 'FLOAT', 'FLOAT'],
|
||||
output_is_list: [false, true, true],
|
||||
output_name: ['INT', 'FLOAT', 'FLOAT']
|
||||
}
|
||||
output_name: ['INT', 'FLOAT', 'FLOAT'],
|
||||
output_node: false
|
||||
} as ComfyNodeDefV1
|
||||
|
||||
const result = new ComfyNodeDefImpl(plainObject)
|
||||
|
||||
expect(result.outputs.all).toEqual([
|
||||
expect(result.outputs).toEqual([
|
||||
{
|
||||
index: 0,
|
||||
name: 'INT',
|
||||
@@ -316,11 +425,12 @@ describe('ComfyNodeDefImpl', () => {
|
||||
input: {},
|
||||
output: ['INT', 'FLOAT', 'STRING'],
|
||||
output_is_list: [false, false, false],
|
||||
output_name: ['output', 'output', 'uniqueOutput']
|
||||
}
|
||||
output_name: ['output', 'output', 'uniqueOutput'],
|
||||
output_node: false
|
||||
} as ComfyNodeDefV1
|
||||
|
||||
const result = new ComfyNodeDefImpl(plainObject)
|
||||
expect(result.outputs.all).toEqual([
|
||||
expect(result.outputs).toEqual([
|
||||
{
|
||||
index: 0,
|
||||
name: 'output',
|
||||
@@ -352,12 +462,13 @@ describe('ComfyNodeDefImpl', () => {
|
||||
input: {},
|
||||
output: [],
|
||||
output_is_list: [],
|
||||
output_name: []
|
||||
}
|
||||
output_name: [],
|
||||
output_node: false
|
||||
} as ComfyNodeDefV1
|
||||
|
||||
const result = new ComfyNodeDefImpl(plainObject)
|
||||
|
||||
expect(result.outputs.all).toEqual([])
|
||||
expect(result.outputs).toEqual([])
|
||||
})
|
||||
|
||||
it('should handle undefined fields', () => {
|
||||
@@ -366,12 +477,13 @@ describe('ComfyNodeDefImpl', () => {
|
||||
display_name: 'Empty Output Node',
|
||||
category: 'Test',
|
||||
python_module: 'test_module',
|
||||
description: 'A node with no outputs'
|
||||
}
|
||||
description: 'A node with no outputs',
|
||||
output_node: false
|
||||
} as ComfyNodeDefV1
|
||||
|
||||
const result = new ComfyNodeDefImpl(plainObject)
|
||||
expect(result.outputs.all).toEqual([])
|
||||
expect(result.inputs.all).toEqual([])
|
||||
expect(result.outputs).toEqual([])
|
||||
expect(Object.keys(result.inputs)).toHaveLength(0)
|
||||
})
|
||||
|
||||
it('should handle complex input specifications', () => {
|
||||
@@ -393,13 +505,17 @@ describe('ComfyNodeDefImpl', () => {
|
||||
},
|
||||
output: ['INT'],
|
||||
output_is_list: [false],
|
||||
output_name: ['result']
|
||||
} as ComfyNodeDef
|
||||
output_name: ['result'],
|
||||
output_node: false
|
||||
} as ComfyNodeDefV1
|
||||
|
||||
const result = new ComfyNodeDefImpl(plainObject)
|
||||
|
||||
expect(result.inputs).toBeInstanceOf(ComfyInputsSpec)
|
||||
expect(result.inputs.required).toBeDefined()
|
||||
expect(result.inputs.optional).toBeDefined()
|
||||
expect(result.inputs).toBeDefined()
|
||||
expect(Object.keys(result.inputs)).toHaveLength(4)
|
||||
expect(result.inputs['intInput']).toBeDefined()
|
||||
expect(result.inputs['stringInput']).toBeDefined()
|
||||
expect(result.inputs['booleanInput']).toBeDefined()
|
||||
expect(result.inputs['floatInput']).toBeDefined()
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user