mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-04 07:00:23 +00:00
## Summary Merges latest changes from `main` as of 10-06-2025. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-5965-Merge-main-as-of-10-06-2025-into-rh-test-2856d73d3650812cb95fd8917278a770) by [Unito](https://www.unito.io) --------- Signed-off-by: Marcel Petrick <mail@marcelpetrick.it> Co-authored-by: filtered <176114999+webfiltered@users.noreply.github.com> Co-authored-by: Christian Byrne <cbyrne@comfy.org> Co-authored-by: github-actions <github-actions@github.com> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Alexander Brown <drjkl@comfy.org> Co-authored-by: Benjamin Lu <benceruleanlu@proton.me> Co-authored-by: Terry Jia <terryjia88@gmail.com> Co-authored-by: snomiao <snomiao@gmail.com> Co-authored-by: Simula_r <18093452+simula-r@users.noreply.github.com> Co-authored-by: Jake Schroeder <jake.schroeder@isophex.com> 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: GitHub Action <action@github.com> Co-authored-by: Johnpaul Chiwetelu <49923152+Myestery@users.noreply.github.com> Co-authored-by: Marcel Petrick <mail@marcelpetrick.it> Co-authored-by: Alexander Brown <DrJKL0424@gmail.com> Co-authored-by: Benjamin Lu <benjaminlu1107@gmail.com> Co-authored-by: Alexander Piskun <13381981+bigcat88@users.noreply.github.com> Co-authored-by: Rizumu Ayaka <rizumu@ayaka.moe> Co-authored-by: JakeSchroeder <jake@axiom.co> Co-authored-by: AustinMroz <austin@comfy.org> Co-authored-by: DrJKL <DrJKL@users.noreply.github.com> Co-authored-by: ComfyUI Wiki <contact@comfyui-wiki.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 not emit events when value doesn't change", () => {
|
|
new LGraphNodeProperties(mockNode)
|
|
|
|
mockNode.title = 'Test Node' // Same value as original
|
|
|
|
expect(mockGraph.trigger).toHaveBeenCalledTimes(0)
|
|
})
|
|
|
|
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()
|
|
})
|
|
})
|
|
})
|