fix: added a missing test, corrected the imports, added behavior for disconnected goals as last step

ref: N25B-434
This commit is contained in:
Björn Otgaar
2026-01-10 11:26:26 +01:00
parent a5a345b9a9
commit 8ffc919e7e
6 changed files with 57 additions and 39 deletions

View File

@@ -1,5 +1,6 @@
import { GoalReduce } from "../nodes/GoalNode"
import { type Node } from "@xyflow/react"
import { GoalReduce } from "../nodes/GoalNode"
export type Plan = {
name: string,

View File

@@ -27,8 +27,9 @@ export function insertGoalInPlan(plan: Plan, goalNode: GoalNode): Plan {
* @param goalID: the goal node to delete.
* @returns: a new plan with the goal removed.
*/
export function deleteGoalInPlanByID(plan: Plan, goalID: string): Plan {
return {...plan,
export function deleteGoalInPlanByID(plan: Plan, goalID: string) {
const updatedPlan = {...plan,
steps: plan.steps.filter((x) => x.id !== goalID)
}
return updatedPlan.steps.length == 0 ? undefined : updatedPlan
}

View File

@@ -6,7 +6,7 @@ import {
import { Toolbar } from '../components/NodeComponents';
import styles from '../../VisProg.module.css';
import {MultiConnectionHandle} from "../components/RuleBasedHandle.tsx";
import {allowOnlyConnectionsFromType} from "../HandleRules.ts";
import {allowOnlyConnectionsFromHandle} from "../HandleRules.ts";
import useFlowStore from '../VisProgStores';
import { TextField } from '../../../../components/TextField';
import { MultilineTextField } from '../../../../components/MultilineTextField';
@@ -185,7 +185,7 @@ export default function BasicBeliefNode(props: NodeProps<BasicBeliefNode>) {
</div>
)}
<MultiConnectionHandle type="source" position={Position.Right} id="source" rules={[
allowOnlyConnectionsFromType(["norm", "trigger"]),
allowOnlyConnectionsFromHandle([{nodeType:"trigger",handleId:"TriggerBeliefs"}, {nodeType:"norm",handleId:"NormBeliefs"}]),
]}/>
</div>
</>

View File

@@ -80,7 +80,7 @@ export default function NormNode(props: NodeProps<NormNode>) {
<MultiConnectionHandle type="source" position={Position.Right} id="norms" rules={[
allowOnlyConnectionsFromHandle([{nodeType:"phase",handleId:"data"}])
]}/>
<SingleConnectionHandle type="target" position={Position.Bottom} id="beliefs" rules={[
<SingleConnectionHandle type="target" position={Position.Bottom} id="NormBeliefs" rules={[
allowOnlyConnectionsFromType(["basic_belief"])
]}/>
</div>

View File

@@ -69,7 +69,7 @@ export default function TriggerNode(props: NodeProps<TriggerNode>) {
<SingleConnectionHandle
type="target"
position={Position.Bottom}
id="beliefs"
id="TriggerBeliefs"
style={{ left: '40%' }}
rules={[
allowOnlyConnectionsFromType(['basic_belief']),

View File

@@ -1,11 +1,15 @@
// PlanEditorDialog.test.tsx
import { describe, it, beforeEach, jest } from '@jest/globals';
import { screen, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { Node } from '@xyflow/react';
import { renderWithProviders } from '../../../../test-utils/test-utils.tsx';
import PlanEditorDialog from '../../../../../src/pages/VisProgPage/visualProgrammingUI/components/PlanEditor';
import { PlanReduce, type Plan } from '../../../../../src/pages/VisProgPage/visualProgrammingUI/components/Plan';
import '@testing-library/jest-dom';
import { GoalReduce, type GoalNodeData } from '../../../../../src/pages/VisProgPage/visualProgrammingUI/nodes/GoalNode.tsx';
import { GoalNodeDefaults } from '../../../../../src/pages/VisProgPage/visualProgrammingUI/nodes/GoalNode.default.ts';
import { insertGoalInPlan } from '../../../../../src/pages/VisProgPage/visualProgrammingUI/components/PlanEditingFunctions.tsx';
// Mock structuredClone
(globalThis as any).structuredClone = jest.fn((val) => JSON.parse(JSON.stringify(val)));
@@ -468,38 +472,50 @@ describe('PlanEditorDialog', () => {
describe('Plan reducing', () => {
it('should correctly reduce the plan given the elements of the plan', () => {
const testplan = extendedPlan
const expectedResult = {
id: "extended-plan-1",
steps: [
{
id: "firststep",
gesture: {
type: "tag",
name: "hello"
}
},
{
id: "secondstep",
gesture: {
type: "single",
name: "somefolder/somegesture"
}
},
{
id: "thirdstep",
goal: "ask the user something or whatever"
},
{
id: "fourthstep",
text: "I'm a cyborg ninja :>"
// Create a plan for testing
const testplan = extendedPlan
const mockGoalNode: Node<GoalNodeData> = {
id: 'goal-1',
type: 'goal',
position: { x: 0, y: 0 },
data: { ...JSON.parse(JSON.stringify(GoalNodeDefaults)), name: 'mock goal', plan: defaultPlan },
};
// Insert the goal and retrieve its expected data
const newTestPlan = insertGoalInPlan(testplan, mockGoalNode)
const goalReduced = GoalReduce(mockGoalNode, [mockGoalNode])
const expectedResult = {
id: "extended-plan-1",
steps: [
{
id: "firststep",
gesture: {
type: "tag",
name: "hello"
}
]
}
},
{
id: "secondstep",
gesture: {
type: "single",
name: "somefolder/somegesture"
}
},
{
id: "thirdstep",
goal: "ask the user something or whatever"
},
{
id: "fourthstep",
text: "I'm a cyborg ninja :>"
},
goalReduced,
]
}
const actualResult = PlanReduce([], testplan) // TODO: FIX THIS TEST :)))
expect(actualResult).toEqual(expectedResult)
// Check to see it the goal got added, and its reduced data was added to the goals'
const actualResult = PlanReduce([mockGoalNode], newTestPlan)
expect(actualResult).toEqual(expectedResult)
});
})
});