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 { type Node } from "@xyflow/react"
import { GoalReduce } from "../nodes/GoalNode"
export type Plan = { export type Plan = {
name: string, name: string,

View File

@@ -27,8 +27,9 @@ export function insertGoalInPlan(plan: Plan, goalNode: GoalNode): Plan {
* @param goalID: the goal node to delete. * @param goalID: the goal node to delete.
* @returns: a new plan with the goal removed. * @returns: a new plan with the goal removed.
*/ */
export function deleteGoalInPlanByID(plan: Plan, goalID: string): Plan { export function deleteGoalInPlanByID(plan: Plan, goalID: string) {
return {...plan, const updatedPlan = {...plan,
steps: plan.steps.filter((x) => x.id !== goalID) 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 { Toolbar } from '../components/NodeComponents';
import styles from '../../VisProg.module.css'; import styles from '../../VisProg.module.css';
import {MultiConnectionHandle} from "../components/RuleBasedHandle.tsx"; import {MultiConnectionHandle} from "../components/RuleBasedHandle.tsx";
import {allowOnlyConnectionsFromType} from "../HandleRules.ts"; import {allowOnlyConnectionsFromHandle} from "../HandleRules.ts";
import useFlowStore from '../VisProgStores'; import useFlowStore from '../VisProgStores';
import { TextField } from '../../../../components/TextField'; import { TextField } from '../../../../components/TextField';
import { MultilineTextField } from '../../../../components/MultilineTextField'; import { MultilineTextField } from '../../../../components/MultilineTextField';
@@ -185,7 +185,7 @@ export default function BasicBeliefNode(props: NodeProps<BasicBeliefNode>) {
</div> </div>
)} )}
<MultiConnectionHandle type="source" position={Position.Right} id="source" rules={[ <MultiConnectionHandle type="source" position={Position.Right} id="source" rules={[
allowOnlyConnectionsFromType(["norm", "trigger"]), allowOnlyConnectionsFromHandle([{nodeType:"trigger",handleId:"TriggerBeliefs"}, {nodeType:"norm",handleId:"NormBeliefs"}]),
]}/> ]}/>
</div> </div>
</> </>

View File

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

View File

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

View File

@@ -1,11 +1,15 @@
// PlanEditorDialog.test.tsx
import { describe, it, beforeEach, jest } from '@jest/globals'; import { describe, it, beforeEach, jest } from '@jest/globals';
import { screen, within } from '@testing-library/react'; import { screen, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event'; import userEvent from '@testing-library/user-event';
import type { Node } from '@xyflow/react';
import { renderWithProviders } from '../../../../test-utils/test-utils.tsx'; import { renderWithProviders } from '../../../../test-utils/test-utils.tsx';
import PlanEditorDialog from '../../../../../src/pages/VisProgPage/visualProgrammingUI/components/PlanEditor'; import PlanEditorDialog from '../../../../../src/pages/VisProgPage/visualProgrammingUI/components/PlanEditor';
import { PlanReduce, type Plan } from '../../../../../src/pages/VisProgPage/visualProgrammingUI/components/Plan'; import { PlanReduce, type Plan } from '../../../../../src/pages/VisProgPage/visualProgrammingUI/components/Plan';
import '@testing-library/jest-dom'; 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 // Mock structuredClone
(globalThis as any).structuredClone = jest.fn((val) => JSON.parse(JSON.stringify(val))); (globalThis as any).structuredClone = jest.fn((val) => JSON.parse(JSON.stringify(val)));
@@ -468,7 +472,18 @@ describe('PlanEditorDialog', () => {
describe('Plan reducing', () => { describe('Plan reducing', () => {
it('should correctly reduce the plan given the elements of the plan', () => { it('should correctly reduce the plan given the elements of the plan', () => {
// Create a plan for testing
const testplan = extendedPlan 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 = { const expectedResult = {
id: "extended-plan-1", id: "extended-plan-1",
steps: [ steps: [
@@ -493,12 +508,13 @@ describe('PlanEditorDialog', () => {
{ {
id: "fourthstep", id: "fourthstep",
text: "I'm a cyborg ninja :>" text: "I'm a cyborg ninja :>"
} },
goalReduced,
] ]
} }
const actualResult = PlanReduce([], testplan) // TODO: FIX THIS TEST :))) // 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) expect(actualResult).toEqual(expectedResult)
}); });
}) })