mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-04 15:10:06 +00:00
## Summary Assorted cleanup opportunities found while working through the Vue node rendering logic cleanup. ## Review Focus Am I wrong that the readonly logic was never actually executing because it was defined as False in GraphCanvas when making each LGraphNode? Is there an edge case or some other reason that the ResizeObserver wouldn't work as a single signal to resize the canvas? ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-5869-Cleanup-YAGNI-readonly-props-private-swap-on-ComfyApp-Canvas-resize-events-simplificat-27e6d73d3650811ba1dcf29e8d43091e) by [Unito](https://www.unito.io) --------- Co-authored-by: github-actions <github-actions@github.com>
210 lines
5.3 KiB
TypeScript
210 lines
5.3 KiB
TypeScript
/**
|
|
* Tests for NodeHeader subgraph functionality
|
|
*/
|
|
import { createTestingPinia } from '@pinia/testing'
|
|
import { mount } from '@vue/test-utils'
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
|
|
import type { VueNodeData } from '@/composables/graph/useGraphNodeManager'
|
|
import NodeHeader from '@/renderer/extensions/vueNodes/components/NodeHeader.vue'
|
|
import { getNodeByLocatorId } from '@/utils/graphTraversalUtil'
|
|
|
|
// Mock dependencies
|
|
vi.mock('@/scripts/app', () => ({
|
|
app: {
|
|
graph: null as any
|
|
}
|
|
}))
|
|
|
|
vi.mock('@/utils/graphTraversalUtil', () => ({
|
|
getNodeByLocatorId: vi.fn(),
|
|
getLocatorIdFromNodeData: vi.fn((nodeData) =>
|
|
nodeData.subgraphId
|
|
? `${nodeData.subgraphId}:${String(nodeData.id)}`
|
|
: String(nodeData.id)
|
|
)
|
|
}))
|
|
|
|
vi.mock('@/composables/useErrorHandling', () => ({
|
|
useErrorHandling: () => ({
|
|
toastErrorHandler: vi.fn()
|
|
})
|
|
}))
|
|
|
|
vi.mock('vue-i18n', () => ({
|
|
useI18n: () => ({
|
|
t: vi.fn((key) => key)
|
|
}),
|
|
createI18n: vi.fn(() => ({
|
|
global: {
|
|
t: vi.fn((key) => key)
|
|
}
|
|
}))
|
|
}))
|
|
|
|
vi.mock('@/i18n', () => ({
|
|
st: vi.fn((key) => key),
|
|
t: vi.fn((key) => key),
|
|
i18n: {
|
|
global: {
|
|
t: vi.fn((key) => key)
|
|
}
|
|
}
|
|
}))
|
|
|
|
describe('NodeHeader - Subgraph Functionality', () => {
|
|
// Helper to setup common mocks
|
|
const setupMocks = async (isSubgraph = true, hasGraph = true) => {
|
|
const { app } = await import('@/scripts/app')
|
|
|
|
if (hasGraph) {
|
|
;(app as any).graph = { rootGraph: {} }
|
|
} else {
|
|
;(app as any).graph = null
|
|
}
|
|
|
|
vi.mocked(getNodeByLocatorId).mockReturnValue({
|
|
isSubgraphNode: () => isSubgraph
|
|
} as any)
|
|
}
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks()
|
|
})
|
|
|
|
const createMockNodeData = (
|
|
id: string,
|
|
subgraphId?: string
|
|
): VueNodeData => ({
|
|
id,
|
|
title: 'Test Node',
|
|
type: 'TestNode',
|
|
mode: 0,
|
|
selected: false,
|
|
executing: false,
|
|
subgraphId,
|
|
widgets: [],
|
|
inputs: [],
|
|
outputs: [],
|
|
hasErrors: false,
|
|
flags: {}
|
|
})
|
|
|
|
const createWrapper = (props = {}) => {
|
|
return mount(NodeHeader, {
|
|
props,
|
|
global: {
|
|
plugins: [createTestingPinia({ createSpy: vi.fn })],
|
|
mocks: {
|
|
$t: vi.fn((key: string) => key),
|
|
$primevue: { config: {} }
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
it('should show subgraph button for subgraph nodes', async () => {
|
|
await setupMocks(true) // isSubgraph = true
|
|
|
|
const wrapper = createWrapper({
|
|
nodeData: createMockNodeData('test-node-1'),
|
|
readonly: false
|
|
})
|
|
|
|
await wrapper.vm.$nextTick()
|
|
|
|
const subgraphButton = wrapper.find('[data-testid="subgraph-enter-button"]')
|
|
expect(subgraphButton.exists()).toBe(true)
|
|
})
|
|
|
|
it('should not show subgraph button for regular nodes', async () => {
|
|
await setupMocks(false) // isSubgraph = false
|
|
|
|
const wrapper = createWrapper({
|
|
nodeData: createMockNodeData('test-node-1'),
|
|
readonly: false
|
|
})
|
|
|
|
await wrapper.vm.$nextTick()
|
|
|
|
const subgraphButton = wrapper.find('[data-testid="subgraph-enter-button"]')
|
|
expect(subgraphButton.exists()).toBe(false)
|
|
})
|
|
|
|
it('should emit enter-subgraph event when button is clicked', async () => {
|
|
await setupMocks(true) // isSubgraph = true
|
|
|
|
const wrapper = createWrapper({
|
|
nodeData: createMockNodeData('test-node-1'),
|
|
readonly: false
|
|
})
|
|
|
|
await wrapper.vm.$nextTick()
|
|
|
|
const subgraphButton = wrapper.find('[data-testid="subgraph-enter-button"]')
|
|
await subgraphButton.trigger('click')
|
|
|
|
expect(wrapper.emitted('enter-subgraph')).toBeTruthy()
|
|
expect(wrapper.emitted('enter-subgraph')).toHaveLength(1)
|
|
})
|
|
|
|
it('should handle subgraph context correctly', async () => {
|
|
await setupMocks(true) // isSubgraph = true
|
|
|
|
const wrapper = createWrapper({
|
|
nodeData: createMockNodeData('test-node-1', 'subgraph-id'),
|
|
readonly: false
|
|
})
|
|
|
|
await wrapper.vm.$nextTick()
|
|
|
|
// Should call getNodeByLocatorId with correct locator ID
|
|
expect(vi.mocked(getNodeByLocatorId)).toHaveBeenCalledWith(
|
|
expect.anything(),
|
|
'subgraph-id:test-node-1'
|
|
)
|
|
|
|
const subgraphButton = wrapper.find('[data-testid="subgraph-enter-button"]')
|
|
expect(subgraphButton.exists()).toBe(true)
|
|
})
|
|
|
|
it('should handle missing graph gracefully', async () => {
|
|
await setupMocks(true, false) // isSubgraph = true, hasGraph = false
|
|
|
|
const wrapper = createWrapper({
|
|
nodeData: createMockNodeData('test-node-1'),
|
|
readonly: false
|
|
})
|
|
|
|
await wrapper.vm.$nextTick()
|
|
|
|
const subgraphButton = wrapper.find('[data-testid="subgraph-enter-button"]')
|
|
expect(subgraphButton.exists()).toBe(false)
|
|
})
|
|
|
|
it('should prevent event propagation on double click', async () => {
|
|
await setupMocks(true) // isSubgraph = true
|
|
|
|
const wrapper = createWrapper({
|
|
nodeData: createMockNodeData('test-node-1'),
|
|
readonly: false
|
|
})
|
|
|
|
await wrapper.vm.$nextTick()
|
|
|
|
const subgraphButton = wrapper.find('[data-testid="subgraph-enter-button"]')
|
|
|
|
// Mock event object
|
|
const mockEvent = {
|
|
stopPropagation: vi.fn()
|
|
}
|
|
|
|
// Trigger dblclick event
|
|
await subgraphButton.trigger('dblclick', mockEvent)
|
|
|
|
// Should prevent propagation (handled by @dblclick.stop directive)
|
|
// This is tested by ensuring the component doesn't error and renders correctly
|
|
expect(subgraphButton.exists()).toBe(true)
|
|
})
|
|
})
|