Skip to content

Commit a1e9af7

Browse files
refactor(agentflow): update import paths and clean up test utilities (#5789)
* refactor(agentflow): update import paths and clean up test utilities - Refactor import paths to use absolute paths (alias) for better readability and maintainability. - Remove unused function `initializeDefaultNodeData` from `nodeFactory` and its related tests. - Update `TESTS.md` to reflect the current testing status of various modules. - Minor adjustments to Vite configuration for improved development experience. * fix markdown format
1 parent a865f43 commit a1e9af7

35 files changed

Lines changed: 116 additions & 138 deletions

packages/agentflow/TESTS.md

Lines changed: 35 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -21,53 +21,56 @@ Add tests when actively working on these files. Each tier reflects impact and te
2121

2222
These modules carry the highest risk. Test in the same PR when modifying.
2323

24+
<!-- prettier-ignore -->
2425
| File | Key exports to test | Status |
25-
|------|-------------------|--------|
26+
| --- | --- | --- |
2627
| `src/core/validation/` | `validateFlow`, `validateNode` — empty flows, missing/multiple starts, disconnected nodes, cycles, required inputs | ✅ Done |
27-
| `src/core/utils/` | `getUniqueNodeId`, `getUniqueNodeLabel`, `initializeDefaultNodeData`, `initNode`, `generateExportFlowData`, `isValidConnectionAgentflowV2` | ✅ Done |
28+
| `src/core/utils/` | `getUniqueNodeId`, `getUniqueNodeLabel`, `initNode`, `generateExportFlowData`, `isValidConnectionAgentflowV2` | ✅ Done |
2829
| `src/core/node-catalog/` | `filterNodesByComponents`, `isAgentflowNode`, `groupNodesByCategory` | ✅ Done |
2930
| `src/core/node-config/` | `getAgentflowIcon`, `getNodeColor` | ✅ Done |
30-
| `src/core/theme/tokens.ts` | All design tokens — node colors (15 types, uniqueness), light/dark variants (backgrounds, borders, text), spacing scale (8px base), semantic colors, ReactFlow colors, shadows, border radius, gradients | ✅ Done |
31-
| `src/core/theme/cssVariables.ts` | `generateCSSVariables()`generates valid CSS strings, includes all variables (colors, spacing, shadows, etc.), correct light/dark mode values, proper formatting (px suffixes), consistency with tokens | ✅ Done |
32-
| `src/core/theme/createAgentflowTheme.ts` | `createAgentflowTheme()` — MUI theme creation, palette mode (light/dark), background/text/border colors from tokens, custom card palette extension, 8px spacing, border radius, theme consistency | ✅ Done |
31+
| `src/core/theme/tokens.ts` | All design tokens — node colors, light/dark variants, spacing scale, semantic colors, ReactFlow colors, shadows, border radius, gradients | ✅ Done |
32+
| `src/core/theme/cssVariables.ts` | `generateCSSVariables()` — valid CSS strings, all variables, correct light/dark values, proper formatting, consistency with tokens | ✅ Done |
33+
| `src/core/theme/createAgentflowTheme.ts` | `createAgentflowTheme()` — MUI theme creation, palette mode, colors from tokens, custom card palette, spacing, border radius, consistency | ✅ Done |
3334
| `src/infrastructure/api/client.ts` | `createApiClient` — headers, auth token, 401 interceptor | ✅ Done |
3435
| `src/infrastructure/api/chatflows.ts` | All CRUD + `generateAgentflow` + `getChatModels`, FlowData serialization | ✅ Done |
3536
| `src/infrastructure/api/nodes.ts` | `getAllNodes`, `getNodeByName`, `getNodeIconUrl` | ✅ Done |
36-
| `src/infrastructure/store/AgentflowContext.tsx` | `agentflowReducer` (all action types), `normalizeNodes`. Remaining: `deleteNode()`, `duplicateNode()`, `updateNodeData()`, `getFlowData()` — React callbacks, test when provider stabilizes | 🟡 Partial |
37-
| `src/useAgentflow.ts` | `getFlow()`, `toJSON()`, `validate()`, `addNode()`, `clear()` | ⬜ Not yet — thin wrapper, test when hook gains own logic |
38-
| `src/features/canvas/hooks/useFlowHandlers.ts` | `onConnect`, `onNodesChange`, `onEdgesChange`, `onAddNode` | ⬜ Not yet — heavily coupled to ReactFlow, test when handlers stabilize |
37+
| `src/infrastructure/store/AgentflowContext.tsx` | `agentflowReducer` (all actions), `normalizeNodes`. Remaining: `deleteNode()`, `duplicateNode()`, `updateNodeData()`, `getFlowData()` | 🟡 Partial |
38+
| `src/useAgentflow.ts` | `getFlow()`, `toJSON()`, `validate()`, `addNode()`, `clear()` | ⬜ Not yet — thin wrapper |
39+
| `src/features/canvas/hooks/useFlowHandlers.ts` | `onConnect`, `onNodesChange`, `onEdgesChange`, `onAddNode` | ⬜ Not yet — coupled to ReactFlow |
3940

4041
### Tier 2 — Feature Hooks & Dialogs
4142

4243
Test when adding features or fixing bugs in these areas.
4344

45+
<!-- prettier-ignore -->
4446
| File | Key exports to test | Status |
45-
|------|-------------------|--------|
47+
| --- | --- | --- |
4648
| `src/features/node-palette/search.ts` | `fuzzyScore`, `searchNodes`, `debounce` | ✅ Done |
4749
| `src/features/canvas/hooks/useFlowNodes.ts` | `useFlowNodes()` — category filtering, component whitelist, error states | ⬜ Not yet |
4850
| `src/features/canvas/hooks/useDragAndDrop.ts` | `useDragAndDrop()` — JSON parse error handling, node init on drop | ⬜ Not yet |
4951
| `src/features/canvas/hooks/useNodeColors.ts` | `useNodeColors()` — color calculations for selected/hover/dark mode | ⬜ Not yet |
5052
| `src/infrastructure/store/ConfigContext.tsx` | `ConfigProvider` — theme detection (light/dark/system), media query listener | ⬜ Not yet |
5153
| `src/features/generator/GenerateFlowDialog.tsx` | Dialog state machine — API call flow, error handling, progress state | ⬜ Not yet |
5254
| `src/features/node-editor/EditNodeDialog.tsx` | Label editing — keyboard handling (Enter/Escape), node data updates | ⬜ Not yet |
53-
| `src/infrastructure/api/hooks/useApi.ts` | `useApi()` — loading/error/data state transitions | ⬜ Not yet — may be deprecated, check before investing |
55+
| `src/infrastructure/api/hooks/useApi.ts` | `useApi()` — loading/error/data state transitions | ⬜ Not yet — may be deprecated |
5456

5557
### Tier 3 — UI Components
5658

5759
Mostly JSX with minimal logic. Only add tests if business logic is introduced.
5860

61+
<!-- prettier-ignore -->
5962
| File | When to add tests | Status |
60-
|------|------------------|--------|
63+
| --- | --- | --- |
6164
| `src/features/node-palette/AddNodesDrawer.tsx` | If category grouping or drag serialization logic changes | ⬜ Not yet |
62-
| `src/features/canvas/components/NodeOutputHandles.tsx` | Has `getMinimumNodeHeight()` pure function — test if calculation logic changes | ⬜ Not yet |
65+
| `src/features/canvas/components/NodeOutputHandles.tsx` | Has `getMinimumNodeHeight()` — test if calculation logic changes | ⬜ Not yet |
6366
| `src/features/canvas/containers/AgentFlowNode.tsx` | If warning state or color logic becomes more complex | ⬜ Not yet |
6467
| `src/features/canvas/containers/AgentFlowEdge.tsx` | If edge deletion or interaction logic changes | ⬜ Not yet |
6568
| `src/features/canvas/containers/IterationNode.tsx` | If resize or dimension calculation logic changes | ⬜ Not yet |
6669
| `src/atoms/ConfirmDialog.tsx` | If promise-based confirmation pattern is modified | ⬜ Not yet |
6770
| `src/atoms/NodeInputHandler.tsx` | If input rendering or position calculation logic changes | ⬜ Not yet |
6871
| `src/features/canvas/components/ConnectionLine.tsx` | If edge label determination logic becomes more complex | ⬜ Not yet |
6972
| `src/features/canvas/components/NodeStatusIndicator.tsx` | If status-to-color/icon mapping expands | ⬜ Not yet |
70-
| `src/Agentflow.tsx` | Integration test — dark mode integration (data-dark-mode attribute, Controls class), ThemeProvider wrapper, theme switching, CSS variables injection/cleanup, header rendering, component structure, generate flow dialog (open/close/onGenerated), imperative ref | ✅ Done |
73+
| `src/Agentflow.tsx` | Integration test — dark mode, ThemeProvider, CSS variables, header rendering, generate flow dialog, imperative ref | ✅ Done |
7174

7275
Files that are pure styling or data constants (`styled.ts`, `nodeIcons.ts`, `MainCard.tsx`, `Input.tsx`, etc.) do not need dedicated tests.
7376

@@ -106,28 +109,29 @@ This custom environment intercepts `require('canvas')` at the module level and r
106109
**ReactFlow Mock** (`src/__mocks__/reactflow.tsx`): Provides mock implementations of ReactFlow components and hooks.
107110

108111
Key features:
109-
- Uses `forwardRef` for MUI `styled()` compatibility (prevents emotion errors)
110-
- Uses `useState` internally to maintain stable references (prevents infinite re-render loops)
111-
- Exports all commonly used ReactFlow components (`Controls`, `MiniMap`, `Background`, etc.)
112-
- Mocks hooks (`useNodesState`, `useEdgesState`, `useReactFlow`)
112+
113+
- Uses `forwardRef` for MUI `styled()` compatibility (prevents emotion errors)
114+
- Uses `useState` internally to maintain stable references (prevents infinite re-render loops)
115+
- Exports all commonly used ReactFlow components (`Controls`, `MiniMap`, `Background`, etc.)
116+
- Mocks hooks (`useNodesState`, `useEdgesState`, `useReactFlow`)
113117

114118
**Axios Mock** (`src/__mocks__/axios.ts`): Prevents network errors by mocking all HTTP requests. Returns empty arrays/objects for all API calls to silence network warnings in tests.
115119

116120
**CSS Mock** (`src/__mocks__/styleMock.js`): Empty object export for CSS imports.
117121

118122
## Configuration
119123

120-
- **Jest config**: `jest.config.js` — two projects: `unit` (node env, `.test.ts`) and `components` (custom jsdom env, `.test.tsx`)
121-
- **Test environment**: Component tests use custom jsdom environment (`src/__test_utils__/jest-environment-jsdom.js`) to handle canvas loading
122-
- **Import aliases**: `@test-utils` maps to `src/__test_utils__` for convenient imports
123-
- **Coverage thresholds**: uniform 80% floor (`branches`, `functions`, `lines`, `statements`) enforced per-path:
124-
- `./src/Agentflow.tsx`
125-
- `./src/core/`
126-
- `./src/features/node-palette/search.ts`
127-
- `./src/infrastructure/api/`
128-
- **Coverage exclusions**:
129-
- `src/__test_utils__/**` — test utilities
130-
- `src/__mocks__/**` — module mocks
131-
- `src/infrastructure/api/hooks/useApi.ts` — potentially deprecated
132-
- **CI**: `pnpm test:coverage` runs in GitHub Actions between lint and build
133-
- **Reports**: `coverage/lcov-report/index.html` for detailed HTML report
124+
- **Jest config**: `jest.config.js` — two projects: `unit` (node env, `.test.ts`) and `components` (custom jsdom env, `.test.tsx`)
125+
- **Test environment**: Component tests use custom jsdom environment (`src/__test_utils__/jest-environment-jsdom.js`) to handle canvas loading
126+
- **Import aliases**: `@test-utils` maps to `src/__test_utils__` for convenient imports
127+
- **Coverage thresholds**: uniform 80% floor (`branches`, `functions`, `lines`, `statements`) enforced per-path:
128+
- `./src/Agentflow.tsx`
129+
- `./src/core/`
130+
- `./src/features/node-palette/search.ts`
131+
- `./src/infrastructure/api/`
132+
- **Coverage exclusions**:
133+
- `src/__test_utils__/**` — test utilities
134+
- `src/__mocks__/**` — module mocks
135+
- `src/infrastructure/api/hooks/useApi.ts` — potentially deprecated
136+
- **CI**: `pnpm test:coverage` runs in GitHub Actions between lint and build
137+
- **Reports**: `coverage/lcov-report/index.html` for detailed HTML report

packages/agentflow/examples/vite.config.ts

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,24 @@ import react from '@vitejs/plugin-react'
33
import path from 'path'
44

55
export default defineConfig({
6-
plugins: [react()],
7-
root: __dirname,
8-
resolve: {
9-
alias: {
10-
// Use the source files directly for development
11-
'@flowise/agentflow': path.resolve(__dirname, '../src'),
6+
plugins: [react()],
7+
root: __dirname,
8+
resolve: {
9+
alias: {
10+
// Use the source files directly for development
11+
'@flowise/agentflow': path.resolve(__dirname, '../src'),
12+
'@': path.resolve(__dirname, '../src')
13+
}
1214
},
13-
},
14-
server: {
15-
port: 5174,
16-
// Watch the parent src directory for changes
17-
watch: {
18-
// Include the agentflow source directory
19-
ignored: ['!**/packages/agentflow/src/**'],
15+
server: {
16+
port: 5174,
17+
// Watch the parent src directory for changes
18+
watch: {
19+
// Include the agentflow source directory
20+
ignored: ['!**/packages/agentflow/src/**']
21+
}
2022
},
21-
},
22-
optimizeDeps: {
23-
include: ['react', 'react-dom', '@mui/material', 'reactflow'],
24-
},
23+
optimizeDeps: {
24+
include: ['react', 'react-dom', '@mui/material', 'reactflow']
25+
}
2526
})

packages/agentflow/src/__test_utils__/factories.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { FlowEdge, FlowNode, NodeData } from '../core/types'
1+
import type { FlowEdge, FlowNode, NodeData } from '@/core/types'
22

33
/**
44
* Create a {@link FlowNode} with sensible defaults.

packages/agentflow/src/atoms/Input.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { ChangeEvent, useState } from 'react'
33
import { IconButton, InputAdornment, SxProps, TextField, Theme } from '@mui/material'
44
import { IconEye, IconEyeOff } from '@tabler/icons-react'
55

6-
import type { InputParam } from '../core/types'
6+
import type { InputParam } from '@/core/types'
77

88
export interface InputProps {
99
inputParam?: InputParam

packages/agentflow/src/atoms/NodeInputHandler.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { styled, useTheme } from '@mui/material/styles'
66
import { tooltipClasses } from '@mui/material/Tooltip'
77
import { IconArrowsMaximize, IconVariable } from '@tabler/icons-react'
88

9-
import type { InputAnchor, InputParam, NodeData } from '../core/types'
9+
import type { InputAnchor, InputParam, NodeData } from '@/core/types'
1010

1111
const CustomWidthTooltip = styled(({ className, ...props }: TooltipProps) => <Tooltip {...props} classes={{ popper: className }} />)({
1212
[`& .${tooltipClasses.tooltip}`]: {

packages/agentflow/src/core/utils/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Node factory - Node ID generation, labeling, and initialization
2-
export { getUniqueNodeId, getUniqueNodeLabel, initializeDefaultNodeData, initNode } from './nodeFactory'
2+
export { getUniqueNodeId, getUniqueNodeLabel, initNode } from './nodeFactory'
33

44
// Connection validation utilities
55
export { isValidConnectionAgentflowV2 } from './connectionValidation'

packages/agentflow/src/core/utils/nodeFactory.test.ts

Lines changed: 4 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { makeFlowNode, makeNodeData } from '@test-utils/factories'
22

33
import type { NodeData } from '../types'
44

5-
import { getUniqueNodeId, getUniqueNodeLabel, initializeDefaultNodeData, initNode } from './nodeFactory'
5+
import { getUniqueNodeId, getUniqueNodeLabel, initNode } from './nodeFactory'
66

77
const makeNode = (id: string, name: string, label: string) => makeFlowNode(id, { data: { id, name, label } })
88

@@ -48,31 +48,6 @@ describe('getUniqueNodeLabel', () => {
4848
})
4949
})
5050

51-
describe('initializeDefaultNodeData', () => {
52-
it('should return empty object for empty params', () => {
53-
expect(initializeDefaultNodeData([])).toEqual({})
54-
})
55-
56-
it('should use default values when provided', () => {
57-
const params = [
58-
{ name: 'temperature', default: 0.7 },
59-
{ name: 'maxTokens', default: 1024 }
60-
]
61-
expect(initializeDefaultNodeData(params)).toEqual({
62-
temperature: 0.7,
63-
maxTokens: 1024
64-
})
65-
})
66-
67-
it('should use empty string when no default is provided', () => {
68-
const params = [{ name: 'apiKey' }, { name: 'model', default: 'gpt-4' }]
69-
expect(initializeDefaultNodeData(params)).toEqual({
70-
apiKey: '',
71-
model: 'gpt-4'
72-
})
73-
})
74-
})
75-
7651
describe('initNode', () => {
7752
it('should set the new node id on the returned data', () => {
7853
const result = initNode(makeNodeData(), 'node_0')
@@ -129,10 +104,9 @@ describe('initNode', () => {
129104
})
130105
const result = initNode(nodeData, 'n1')
131106
expect(result.inputs!['temp']).toBe(0.7)
132-
// initNode only sets defaults for params with an explicit `default` value,
133-
// unlike initializeDefaultNodeData which falls back to ''. Params without
134-
// a default are intentionally omitted so the UI can distinguish "unset" from "empty".
135-
expect(result.inputs!['model']).toBeUndefined()
107+
// Params without a default fall back to '' (matching agentflow v2 behavior).
108+
// This ensures show/hide conditions can evaluate against a defined value.
109+
expect(result.inputs!['model']).toBe('')
136110
})
137111

138112
it('should preserve existing inputs over defaults', () => {

packages/agentflow/src/core/utils/nodeFactory.ts

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ export function getUniqueNodeId(nodeData: NodeData, nodes: FlowNode[]): string {
1515
return baseId
1616
}
1717

18-
// TODO: Integrate with node drop/creation flow to assign unique labels per node type
1918
/**
2019
* Generate a unique node label based on existing nodes
2120
*/
@@ -34,11 +33,11 @@ export function getUniqueNodeLabel(nodeData: NodeData, nodes: FlowNode[]): strin
3433
return `${nodeData.label} ${suffix}`
3534
}
3635

37-
// TODO: Integrate with node drop/creation flow to populate default input values
3836
/**
39-
* Initialize default values for node parameters
37+
* Initialize default values for node parameters.
38+
* Falls back to '' for params without a default — needed by show/hide condition evaluation.
4039
*/
41-
export function initializeDefaultNodeData(nodeParams: Array<{ name: string; default?: unknown }>): Record<string, unknown> {
40+
function initializeDefaultNodeData(nodeParams: Array<{ name: string; default?: unknown }>): Record<string, unknown> {
4241
const initialValues: Record<string, unknown> = {}
4342

4443
for (const input of nodeParams) {
@@ -117,13 +116,8 @@ export function initNode(nodeData: NodeData, newNodeId: string, isAgentflow = tr
117116
// Initialize outputs
118117
const outputAnchors = isAgentflow ? createAgentFlowOutputs(nodeData, newNodeId) : []
119118

120-
// Initialize default input values
121-
const initialInputs: Record<string, unknown> = {}
122-
for (const param of inputParams) {
123-
if (param.default !== undefined) {
124-
initialInputs[param.name] = param.default
125-
}
126-
}
119+
// Initialize default input values (matches agentflow v2 — falls back to '' for show/hide conditions)
120+
const initialInputs = initializeDefaultNodeData(inputParams)
127121

128122
// Create initialized node data
129123
const initializedData: NodeData = {

packages/agentflow/src/features/canvas/components/AgentflowHeader.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { HeaderRenderProps, ValidationResult } from '../../../core/types'
1+
import type { HeaderRenderProps, ValidationResult } from '@/core/types'
22

33
export interface AgentflowHeaderProps extends HeaderRenderProps {
44
readOnly?: boolean

packages/agentflow/src/features/canvas/components/ConnectionLine.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { EdgeLabelRenderer, getBezierPath, Position, useStore } from 'reactflow'
33

44
import { useTheme } from '@mui/material/styles'
55

6-
import { AGENTFLOW_ICONS } from '../../../core'
6+
import { AGENTFLOW_ICONS } from '@/core'
77

88
interface EdgeLabelProps {
99
transform: string

0 commit comments

Comments
 (0)