mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-03 14:54:37 +00:00
## Summary Tested these changes and confirmed that: 1. Feedback button shows. 2. You can run workflows and switch out models. 3. You can use the mask editor. (thank you @ric-yu for helping me verify). ## Changes A lot, please see commits. Gets us up to date with `main` as of 10-11-2025. --------- Co-authored-by: Simula_r <18093452+simula-r@users.noreply.github.com> Co-authored-by: github-actions <github-actions@github.com> Co-authored-by: snomiao <snomiao@gmail.com> Co-authored-by: Christian Byrne <cbyrne@comfy.org> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: DrJKL <DrJKL@users.noreply.github.com> Co-authored-by: Alexander Brown <drjkl@comfy.org> Co-authored-by: Marwan Ahmed <155799754+marawan206@users.noreply.github.com> Co-authored-by: DrJKL <DrJKL0424@gmail.com> Co-authored-by: Rizumu Ayaka <rizumu@ayaka.moe> Co-authored-by: Comfy Org PR Bot <snomiao+comfy-pr@gmail.com> Co-authored-by: AustinMroz <4284322+AustinMroz@users.noreply.github.com> Co-authored-by: Austin Mroz <austin@comfy.org> Co-authored-by: Johnpaul Chiwetelu <49923152+Myestery@users.noreply.github.com> Co-authored-by: GitHub Action <action@github.com> Co-authored-by: filtered <176114999+webfiltered@users.noreply.github.com> Co-authored-by: Benjamin Lu <benceruleanlu@proton.me> Co-authored-by: Jin Yi <jin12cc@gmail.com> Co-authored-by: Robin Huang <robin.j.huang@gmail.com>
153 lines
4.3 KiB
TypeScript
153 lines
4.3 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
|
|
import { LGraphNodeProperties } from '@/lib/litegraph/src/LGraphNodeProperties'
|
|
|
|
describe('LGraphNodeProperties', () => {
|
|
let mockNode: any
|
|
let mockGraph: any
|
|
|
|
beforeEach(() => {
|
|
mockGraph = {
|
|
trigger: vi.fn()
|
|
}
|
|
|
|
mockNode = {
|
|
id: 123,
|
|
title: 'Test Node',
|
|
flags: {},
|
|
graph: mockGraph
|
|
}
|
|
})
|
|
|
|
describe('property tracking', () => {
|
|
it('should track changes to existing properties', () => {
|
|
new LGraphNodeProperties(mockNode)
|
|
|
|
mockNode.title = 'New Title'
|
|
|
|
expect(mockGraph.trigger).toHaveBeenCalledWith('node:property:changed', {
|
|
nodeId: mockNode.id,
|
|
property: 'title',
|
|
oldValue: 'Test Node',
|
|
newValue: 'New Title'
|
|
})
|
|
})
|
|
|
|
it('should track changes to nested properties', () => {
|
|
new LGraphNodeProperties(mockNode)
|
|
|
|
mockNode.flags.collapsed = true
|
|
|
|
expect(mockGraph.trigger).toHaveBeenCalledWith('node:property:changed', {
|
|
nodeId: mockNode.id,
|
|
property: 'flags.collapsed',
|
|
oldValue: undefined,
|
|
newValue: true
|
|
})
|
|
})
|
|
|
|
it('should emit event when value is set to the same value', () => {
|
|
new LGraphNodeProperties(mockNode)
|
|
|
|
mockNode.title = 'Test Node' // Same value as original
|
|
|
|
expect(mockGraph.trigger).toHaveBeenCalledTimes(1)
|
|
})
|
|
|
|
it('should not emit events when node has no graph', () => {
|
|
mockNode.graph = null
|
|
new LGraphNodeProperties(mockNode)
|
|
|
|
// Should not throw
|
|
expect(() => {
|
|
mockNode.title = 'New Title'
|
|
}).not.toThrow()
|
|
})
|
|
})
|
|
|
|
describe('isTracked', () => {
|
|
it('should correctly identify tracked properties', () => {
|
|
const propManager = new LGraphNodeProperties(mockNode)
|
|
|
|
expect(propManager.isTracked('title')).toBe(true)
|
|
expect(propManager.isTracked('flags.collapsed')).toBe(true)
|
|
expect(propManager.isTracked('untracked')).toBe(false)
|
|
})
|
|
})
|
|
|
|
describe('serialization behavior', () => {
|
|
it('should not make non-existent properties enumerable', () => {
|
|
new LGraphNodeProperties(mockNode)
|
|
|
|
// flags.collapsed doesn't exist initially
|
|
const descriptor = Object.getOwnPropertyDescriptor(
|
|
mockNode.flags,
|
|
'collapsed'
|
|
)
|
|
expect(descriptor?.enumerable).toBe(false)
|
|
})
|
|
|
|
it('should make properties enumerable when set to non-default values', () => {
|
|
new LGraphNodeProperties(mockNode)
|
|
|
|
mockNode.flags.collapsed = true
|
|
|
|
const descriptor = Object.getOwnPropertyDescriptor(
|
|
mockNode.flags,
|
|
'collapsed'
|
|
)
|
|
expect(descriptor?.enumerable).toBe(true)
|
|
})
|
|
|
|
it('should make properties non-enumerable when set back to undefined', () => {
|
|
new LGraphNodeProperties(mockNode)
|
|
|
|
mockNode.flags.collapsed = true
|
|
mockNode.flags.collapsed = undefined
|
|
|
|
const descriptor = Object.getOwnPropertyDescriptor(
|
|
mockNode.flags,
|
|
'collapsed'
|
|
)
|
|
expect(descriptor?.enumerable).toBe(false)
|
|
})
|
|
|
|
it('should keep existing properties enumerable', () => {
|
|
// title exists initially
|
|
const initialDescriptor = Object.getOwnPropertyDescriptor(
|
|
mockNode,
|
|
'title'
|
|
)
|
|
expect(initialDescriptor?.enumerable).toBe(true)
|
|
|
|
new LGraphNodeProperties(mockNode)
|
|
|
|
const afterDescriptor = Object.getOwnPropertyDescriptor(mockNode, 'title')
|
|
expect(afterDescriptor?.enumerable).toBe(true)
|
|
})
|
|
|
|
it('should only include non-undefined values in JSON.stringify', () => {
|
|
new LGraphNodeProperties(mockNode)
|
|
|
|
// Initially, flags.collapsed shouldn't appear
|
|
let json = JSON.parse(JSON.stringify(mockNode))
|
|
expect(json.flags.collapsed).toBeUndefined()
|
|
|
|
// After setting to true, it should appear
|
|
mockNode.flags.collapsed = true
|
|
json = JSON.parse(JSON.stringify(mockNode))
|
|
expect(json.flags.collapsed).toBe(true)
|
|
|
|
// After setting to false, it should still appear (false is not undefined)
|
|
mockNode.flags.collapsed = false
|
|
json = JSON.parse(JSON.stringify(mockNode))
|
|
expect(json.flags.collapsed).toBe(false)
|
|
|
|
// After setting back to undefined, it should disappear
|
|
mockNode.flags.collapsed = undefined
|
|
json = JSON.parse(JSON.stringify(mockNode))
|
|
expect(json.flags.collapsed).toBeUndefined()
|
|
})
|
|
})
|
|
})
|