[Subgraph] Add subgraph breadcrumbs component (#3241)

Co-authored-by: filtered <176114999+webfiltered@users.noreply.github.com>
This commit is contained in:
Christian Byrne
2025-05-02 16:31:45 -07:00
committed by GitHub
parent 111fdcc71a
commit 743f3cb5a1
5 changed files with 248 additions and 5 deletions

View File

@@ -1,7 +1,9 @@
import { createPinia, setActivePinia } from 'pinia'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { nextTick } from 'vue'
import { api } from '@/scripts/api'
import { app as comfyApp } from '@/scripts/app'
import { defaultGraph, defaultGraphJSON } from '@/scripts/defaultGraph'
import {
ComfyWorkflow,
@@ -15,7 +17,16 @@ vi.mock('@/scripts/api', () => ({
api: {
getUserData: vi.fn(),
storeUserData: vi.fn(),
listUserDataFullInfo: vi.fn()
listUserDataFullInfo: vi.fn(),
apiURL: vi.fn(),
addEventListener: vi.fn()
}
}))
// Mock comfyApp globally for the store setup
vi.mock('@/scripts/app', () => ({
app: {
canvas: null // Start with canvas potentially undefined or null
}
}))
@@ -448,4 +459,117 @@ describe('useWorkflowStore', () => {
expect(newWorkflow.isModified).toBe(false)
})
})
describe('Subgraphs', () => {
beforeEach(async () => {
// Ensure canvas exists for these tests
vi.mocked(comfyApp).canvas = { subgraph: null } as any
// Setup an active workflow as updateActiveGraph depends on it
const workflow = store.createTemporary('test-subgraph-workflow.json')
// Mock load to avoid actual file operations/parsing
vi.spyOn(workflow, 'load').mockImplementation(async () => {
workflow.changeTracker = { activeState: {} } as any // Minimal mock
workflow.originalContent = '{}'
workflow.content = '{}'
return workflow as LoadedComfyWorkflow
})
await store.openWorkflow(workflow)
// Reset mocks before each subgraph test
vi.mocked(comfyApp.canvas).subgraph = undefined // Use undefined for root graph
})
it('should handle when comfyApp.canvas is not available', async () => {
// Arrange
vi.mocked(comfyApp).canvas = null as any // Simulate canvas not ready
// Act
console.debug(store.isSubgraphActive)
store.updateActiveGraph()
await nextTick()
// Assert
console.debug(store.isSubgraphActive)
expect(store.isSubgraphActive).toBe(false) // Should default to false
expect(store.subgraphNamePath).toEqual([]) // Should default to empty
})
it('should correctly update state when the root graph is active', async () => {
// Arrange: Ensure comfyApp indicates root graph is active
vi.mocked(comfyApp.canvas).subgraph = undefined // Use undefined for root graph
// Act: Trigger the update
store.updateActiveGraph()
await nextTick() // Wait for Vue reactivity
// Assert: Check store state
expect(store.isSubgraphActive).toBe(false)
expect(store.subgraphNamePath).toEqual([]) // Path is empty for root graph
})
it('should correctly update state when a subgraph is active', async () => {
// Arrange: Setup mock subgraph structure
const mockSubgraph = {
name: 'Level 2 Subgraph',
isRootGraph: false,
pathToRootGraph: [
{ name: 'Root' }, // Root Graph (index 0, ignored)
{ name: 'Level 1 Subgraph' },
{ name: 'Level 2 Subgraph' }
]
}
vi.mocked(comfyApp.canvas).subgraph = mockSubgraph as any
// Act: Trigger the update
store.updateActiveGraph()
await nextTick() // Wait for Vue reactivity
// Assert: Check store state
expect(store.isSubgraphActive).toBe(true)
expect(store.subgraphNamePath).toEqual([
'Level 1 Subgraph',
'Level 2 Subgraph'
]) // Path excludes the root
})
it('should update automatically when activeWorkflow changes', async () => {
// Arrange: Set initial canvas state (e.g., a subgraph)
const initialSubgraph = {
name: 'Initial Subgraph',
pathToRootGraph: [{ name: 'Root' }, { name: 'Initial Subgraph' }],
isRootGraph: false
}
vi.mocked(comfyApp.canvas).subgraph = initialSubgraph as any
// Trigger initial update based on the *first* workflow opened in beforeEach
store.updateActiveGraph()
await nextTick()
// Verify initial state
expect(store.isSubgraphActive).toBe(true)
expect(store.subgraphNamePath).toEqual(['Initial Subgraph'])
// Act: Change the active workflow
const workflow2 = store.createTemporary('workflow2.json')
// Mock load for the second workflow
vi.spyOn(workflow2, 'load').mockImplementation(async () => {
workflow2.changeTracker = { activeState: {} } as any
workflow2.originalContent = '{}'
workflow2.content = '{}'
return workflow2 as LoadedComfyWorkflow
})
// Before changing workflow, set the canvas state to something different (e.g., root)
// This ensures the watcher *does* cause a state change we can assert
vi.mocked(comfyApp.canvas).subgraph = undefined
await store.openWorkflow(workflow2) // This changes activeWorkflow and triggers the watch
await nextTick() // Allow watcher and potential async operations in updateActiveGraph to complete
// Assert: Check that the state was updated by the watcher based on the *new* canvas state
expect(store.isSubgraphActive).toBe(false) // Should reflect the change to undefined subgraph
expect(store.subgraphNamePath).toEqual([]) // Path should be empty for root
})
})
})