import type { SubGraphProps } from '../types' import type { Shape as HooksStoreShape } from '@/app/components/workflow/hooks-store' import type { NestedNodeConfig } from '@/app/components/workflow/nodes/_base/types' import type { LLMNodeType } from '@/app/components/workflow/nodes/llm/types' import type { Node, NodeOutPutVar, ValueSelector } from '@/app/components/workflow/types' import { render } from '@testing-library/react' import { beforeEach, describe, expect, it, vi } from 'vitest' import { NULL_STRATEGY } from '@/app/components/workflow/nodes/_base/constants' import { FlowType } from '@/types/common' import SubGraph from '../index' const mockSetParentAvailableVars = vi.fn() const mockSetParentAvailableNodes = vi.fn() const mockUseSubGraphNodes = vi.fn() const mockSubGraphMain = vi.fn() vi.mock('@/app/components/workflow', () => ({ default: ({ children }: { children: React.ReactNode }) =>
{children}
, })) vi.mock('@/app/components/workflow/context', () => ({ WorkflowContextProvider: ({ children, injectWorkflowStoreSliceFn, }: { children: React.ReactNode injectWorkflowStoreSliceFn: unknown }) => (
{children}
), })) vi.mock('@/app/components/workflow/store', () => ({ useStore: (selector: (state: { setParentAvailableVars: typeof mockSetParentAvailableVars setParentAvailableNodes: typeof mockSetParentAvailableNodes }) => unknown) => selector({ setParentAvailableVars: mockSetParentAvailableVars, setParentAvailableNodes: mockSetParentAvailableNodes, }), })) vi.mock('../hooks', () => ({ useSubGraphNodes: (...args: unknown[]) => mockUseSubGraphNodes(...args), })) vi.mock('../components/sub-graph-main', () => ({ default: (props: unknown) => { mockSubGraphMain(props) return
}, })) const nestedNodeConfig: NestedNodeConfig = { extractor_node_id: 'extractor-1', output_selector: ['extractor-1', 'output'], null_strategy: NULL_STRATEGY.RAISE_ERROR, default_value: '', } const parentAvailableNodes = [{ id: 'node-1' }] as Node[] const parentAvailableVars: NodeOutPutVar[] = [{ nodeId: 'node-1', title: 'Node 1', vars: [] }] const configsMap: HooksStoreShape['configsMap'] = { flowId: 'flow-1', flowType: FlowType.appFlow, } const sourceVariable = ['agent-1', 'context'] as ValueSelector const extractorNode = { id: 'extractor-1', data: { prompt_template: { role: 'user', text: 'ignored' } }, } as Node const assembleProps: SubGraphProps = { variant: 'assemble', title: 'Assembler', isOpen: true, toolNodeId: 'tool-node', paramKey: 'question', parentAvailableNodes, parentAvailableVars, configsMap, nestedNodeConfig, onNestedNodeConfigChange: vi.fn(), } describe('SubGraph', () => { beforeEach(() => { vi.clearAllMocks() mockUseSubGraphNodes.mockReturnValue({ nodes: [{ id: 'render-node' }], edges: [{ id: 'render-edge' }], }) }) it('should inject the sub-graph slice and sync parent availability data', () => { render() expect(mockSetParentAvailableVars).toHaveBeenCalledWith(assembleProps.parentAvailableVars) expect(mockSetParentAvailableNodes).toHaveBeenCalledWith(assembleProps.parentAvailableNodes) }) it('should render the assemble variant with the derived extractor node id', () => { render() expect(mockSubGraphMain).toHaveBeenCalledWith(expect.objectContaining({ variant: 'assemble', title: 'Assembler', extractorNodeId: 'tool-node_ext_question', nodes: [{ id: 'render-node' }], edges: [{ id: 'render-edge' }], })) }) it('should render the agent variant with forwarded nested node config props', () => { const onNestedNodeConfigChange = vi.fn() render( , ) expect(mockSubGraphMain).toHaveBeenCalledWith(expect.objectContaining({ variant: 'agent', title: 'Agent Runner', extractorNodeId: 'agent-tool_ext_context', nestedNodeConfig, onNestedNodeConfigChange, })) }) })