185 lines
6.0 KiB
TypeScript
185 lines
6.0 KiB
TypeScript
import { describe, it, beforeEach } from '@jest/globals';
|
|
import { screen } from '@testing-library/react';
|
|
import { renderWithProviders } from '../../../../test-utils/test-utils.tsx';
|
|
import TriggerNode, {
|
|
TriggerReduce,
|
|
type TriggerNodeData,
|
|
TriggerConnectionSource, TriggerConnectionTarget
|
|
} from '../../../../../src/pages/VisProgPage/visualProgrammingUI/nodes/TriggerNode';
|
|
import useFlowStore from '../../../../../src/pages/VisProgPage/visualProgrammingUI/VisProgStores';
|
|
import type { Node } from '@xyflow/react';
|
|
import '@testing-library/jest-dom';
|
|
import { TriggerNodeDefaults } from '../../../../../src/pages/VisProgPage/visualProgrammingUI/nodes/TriggerNode.default.ts';
|
|
import { BasicBeliefNodeDefaults } from '../../../../../src/pages/VisProgPage/visualProgrammingUI/nodes/BasicBeliefNode.default.ts';
|
|
import { defaultPlan } from '../../../../../src/pages/VisProgPage/visualProgrammingUI/components/Plan.default.ts';
|
|
import { NormNodeDefaults } from '../../../../../src/pages/VisProgPage/visualProgrammingUI/nodes/NormNode.default.ts';
|
|
import { GoalNodeDefaults } from '../../../../../src/pages/VisProgPage/visualProgrammingUI/nodes/GoalNode.default.ts';
|
|
import { act } from 'react-dom/test-utils';
|
|
|
|
describe('TriggerNode', () => {
|
|
|
|
beforeEach(() => {
|
|
jest.clearAllMocks();
|
|
});
|
|
|
|
describe('Rendering', () => {
|
|
it('should render TriggerNode with keywords type', () => {
|
|
const mockNode: Node<TriggerNodeData> = {
|
|
id: 'trigger-1',
|
|
type: 'trigger',
|
|
position: { x: 0, y: 0 },
|
|
data: {
|
|
...JSON.parse(JSON.stringify(TriggerNodeDefaults)),
|
|
},
|
|
};
|
|
|
|
renderWithProviders(
|
|
<TriggerNode
|
|
id={mockNode.id}
|
|
type={mockNode.type as string}
|
|
data={mockNode.data as any}
|
|
selected={false}
|
|
isConnectable={true}
|
|
zIndex={0}
|
|
dragging={false}
|
|
selectable={true}
|
|
deletable={true}
|
|
draggable={true}
|
|
positionAbsoluteX={0}
|
|
positionAbsoluteY={0}
|
|
/>
|
|
);
|
|
|
|
expect(screen.getByText(/Triggers when the condition is met/i)).toBeInTheDocument();
|
|
expect(screen.getByText(/Belief is currently/i)).toBeInTheDocument();
|
|
expect(screen.getByText(/Plan is currently/i)).toBeInTheDocument();
|
|
});
|
|
});
|
|
|
|
describe('TriggerReduce Function', () => {
|
|
it('should reduce a trigger node to its essential data', () => {
|
|
const conditionNode: Node = {
|
|
id: 'belief-1',
|
|
type: 'basic_belief',
|
|
position: { x: 0, y: 0 },
|
|
data: {
|
|
...JSON.parse(JSON.stringify(BasicBeliefNodeDefaults)),
|
|
},
|
|
};
|
|
|
|
const triggerNode: Node = {
|
|
id: 'trigger-1',
|
|
type: 'trigger',
|
|
position: { x: 0, y: 0 },
|
|
data: {
|
|
...JSON.parse(JSON.stringify(TriggerNodeDefaults)),
|
|
condition: "belief-1",
|
|
plan: defaultPlan,
|
|
name: "trigger-1"
|
|
},
|
|
};
|
|
|
|
useFlowStore.setState({
|
|
nodes: [conditionNode, triggerNode],
|
|
edges: [],
|
|
});
|
|
|
|
useFlowStore.getState().onConnect({
|
|
source: 'belief-1',
|
|
target: 'trigger-1',
|
|
sourceHandle: null,
|
|
targetHandle: null,
|
|
});
|
|
|
|
const result = TriggerReduce(triggerNode, useFlowStore.getState().nodes);
|
|
|
|
expect(result).toEqual({
|
|
id: 'trigger-1',
|
|
name: "trigger-1",
|
|
condition: {
|
|
id: "belief-1",
|
|
keyword: "",
|
|
},
|
|
plan: {
|
|
id: expect.anything(),
|
|
steps: [],
|
|
},});
|
|
});
|
|
});
|
|
|
|
|
|
describe('TriggerConnects Function', () => {
|
|
it('should handle connection without errors', () => {
|
|
const node1: Node = {
|
|
id: 'trigger-1',
|
|
type: 'trigger',
|
|
position: { x: 0, y: 0 },
|
|
data: {
|
|
...JSON.parse(JSON.stringify(TriggerNodeDefaults)),
|
|
label: 'Trigger 1',
|
|
},
|
|
};
|
|
|
|
const node2: Node = {
|
|
id: 'norm-1',
|
|
type: 'norm',
|
|
position: { x: 100, y: 0 },
|
|
data: {
|
|
...JSON.parse(JSON.stringify(NormNodeDefaults)),
|
|
label: 'Norm 1',
|
|
},
|
|
};
|
|
|
|
expect(() => {
|
|
TriggerConnectionSource(node1, node2.id);
|
|
TriggerConnectionTarget(node1, node2.id);
|
|
}).not.toThrow();
|
|
});
|
|
});
|
|
|
|
|
|
describe('TriggerConnects Function', () => {
|
|
it('should correctly remove a goal from the triggers plan after it has been disconnected', () => {
|
|
// first, define the goal node and trigger node.
|
|
const goal: Node = {
|
|
id: 'g-1',
|
|
type: 'goal',
|
|
position: { x: 0, y: 0 },
|
|
data: { ...JSON.parse(JSON.stringify(GoalNodeDefaults)), name: 'Goal 1' },
|
|
};
|
|
|
|
const trigger: Node<TriggerNodeData> = {
|
|
id: 'trigger-1',
|
|
type: 'trigger',
|
|
position: { x: 0, y: 0 },
|
|
data: { ...JSON.parse(JSON.stringify(TriggerNodeDefaults)) },
|
|
};
|
|
|
|
// set initial store
|
|
useFlowStore.setState({ nodes: [goal, trigger], edges: [] });
|
|
|
|
// then, connect the goal to the trigger.
|
|
act(() => {
|
|
useFlowStore.getState().onConnect({ source: 'g-1', target: 'trigger-1', sourceHandle: null, targetHandle: null });
|
|
});
|
|
|
|
// expect the goal id to be part of a goal step of the plan.
|
|
let updatedTrigger = useFlowStore.getState().nodes.find((n) => n.id === 'trigger-1');
|
|
expect(updatedTrigger?.data.plan).toBeDefined();
|
|
const plan = updatedTrigger?.data.plan as any;
|
|
expect(plan.steps.find((s: any) => s.id === 'g-1')).toBeDefined();
|
|
|
|
// then, disconnect the goal from the trigger.
|
|
act(() => {
|
|
useFlowStore.getState().onEdgesDelete([{ id: 'g-1-trigger-1', source: 'g-1', target: 'trigger-1' } as any]);
|
|
});
|
|
|
|
// finally, expect the goal id to NOT be part of the goal step of the plan.
|
|
updatedTrigger = useFlowStore.getState().nodes.find((n) => n.id === 'trigger-1');
|
|
const planAfter = updatedTrigger?.data.plan as any;
|
|
const stillHas = planAfter?.steps?.find((s: any) => s.id === 'g-1');
|
|
expect(stillHas).toBeUndefined();
|
|
});
|
|
});
|
|
});
|