// import type {Edge} from "@xyflow/react"; // import type {PreparedPhase} from "../../../../src/pages/VisProgPage/visualProgrammingUI/GraphReducerTypes.ts"; // import useFlowStore from "../../../../src/pages/VisProgPage/visualProgrammingUI/VisProgStores.tsx"; // import type {AppNode} from "../../../../src/pages/VisProgPage/visualProgrammingUI/VisProgTypes.tsx"; // // sets of default values for nodes and edges to be used for test cases // type FlowState = { // name: string; // nodes: AppNode[]; // edges: Edge[]; // }; // // predefined graphs for testing: // const onlyOnePhase : FlowState = { // name: "onlyOnePhase", // nodes: [ // { // id: 'start', // type: 'start', // position: {x: 0, y: 0}, // data: {label: 'start'} // }, // { // id: 'phase-1', // type: 'phase', // position: {x: 0, y: 150}, // data: {label: 'Generic Phase', number: 1}, // }, // { // id: 'end', // type: 'end', // position: {x: 0, y: 300}, // data: {label: 'End'} // } // ], // edges:[ // { // id: 'start-phase-1', // source: 'start', // target: 'phase-1', // }, // { // id: 'phase-1-end', // source: 'phase-1', // target: 'end', // } // ] // }; // const onlyThreePhases : FlowState = { // name: "onlyThreePhases", // nodes: [ // { // id: 'start', // type: 'start', // position: {x: 0, y: 0}, // data: {label: 'start'} // }, // { // id: 'phase-1', // type: 'phase', // position: {x: 0, y: 150}, // data: {label: 'Generic Phase', number: 1}, // }, // { // id: 'phase-3', // type: 'phase', // position: {x: 0, y: 150}, // data: {label: 'Generic Phase', number: 3}, // }, // { // id: 'phase-2', // type: 'phase', // position: {x: 0, y: 150}, // data: {label: 'Generic Phase', number: 2}, // }, // { // id: 'end', // type: 'end', // position: {x: 0, y: 300}, // data: {label: 'End'} // } // ], // edges:[ // { // id: 'start-phase-1', // source: 'start', // target: 'phase-1', // }, // { // id: 'phase-1-phase-2', // source: 'phase-1', // target: 'phase-2', // }, // { // id: 'phase-2-phase-3', // source: 'phase-2', // target: 'phase-3', // }, // { // id: 'phase-3-end', // source: 'phase-3', // target: 'end', // } // ] // }; // const onlySingleEdgeNorms : FlowState = { // name: "onlySingleEdgeNorms", // nodes: [ // { // id: 'start', // type: 'start', // position: {x: 0, y: 0}, // data: {label: 'start'} // }, // { // id: 'phase-1', // type: 'phase', // position: {x: 0, y: 150}, // data: {label: 'Generic Phase', number: 1}, // }, // { // id: 'norm-1', // type: 'norm', // position: {x: 0, y: 150}, // data: {label: 'Generic Norm', value: "generic"}, // }, // { // id: 'norm-2', // type: 'norm', // position: {x: 0, y: 150}, // data: {label: 'Generic Norm', value: "generic"}, // }, // { // id: 'phase-3', // type: 'phase', // position: {x: 0, y: 150}, // data: {label: 'Generic Phase', number: 3}, // }, // { // id: 'phase-2', // type: 'phase', // position: {x: 0, y: 150}, // data: {label: 'Generic Phase', number: 2}, // }, // { // id: 'end', // type: 'end', // position: {x: 0, y: 300}, // data: {label: 'End'} // } // ], // edges:[ // { // id: 'start-phase-1', // source: 'start', // target: 'phase-1', // }, // { // id: 'norm-1-phase-2', // source: 'norm-1', // target: 'phase-2', // }, // { // id: 'phase-1-phase-2', // source: 'phase-1', // target: 'phase-2', // }, // { // id: 'phase-2-phase-3', // source: 'phase-2', // target: 'phase-3', // }, // { // id: 'norm-2-phase-3', // source: 'norm-2', // target: 'phase-3', // }, // { // id: 'phase-3-end', // source: 'phase-3', // target: 'end', // } // ] // }; // const multiEdgeNorms : FlowState = { // name: "multiEdgeNorms", // nodes: [ // { // id: 'start', // type: 'start', // position: {x: 0, y: 0}, // data: {label: 'start'} // }, // { // id: 'phase-1', // type: 'phase', // position: {x: 0, y: 150}, // data: {label: 'Generic Phase', number: 1}, // }, // { // id: 'norm-1', // type: 'norm', // position: {x: 0, y: 150}, // data: {label: 'Generic Norm', value: "generic"}, // }, // { // id: 'norm-2', // type: 'norm', // position: {x: 0, y: 150}, // data: {label: 'Generic Norm', value: "generic"}, // }, // { // id: 'phase-3', // type: 'phase', // position: {x: 0, y: 150}, // data: {label: 'Generic Phase', number: 3}, // }, // { // id: 'norm-3', // type: 'norm', // position: {x: 0, y: 150}, // data: {label: 'Generic Norm', value: "generic"}, // }, // { // id: 'phase-2', // type: 'phase', // position: {x: 0, y: 150}, // data: {label: 'Generic Phase', number: 2}, // }, // { // id: 'end', // type: 'end', // position: {x: 0, y: 300}, // data: {label: 'End'} // } // ], // edges:[ // { // id: 'start-phase-1', // source: 'start', // target: 'phase-1', // }, // { // id: 'norm-1-phase-2', // source: 'norm-1', // target: 'phase-2', // }, // { // id: 'norm-1-phase-3', // source: 'norm-1', // target: 'phase-3', // }, // { // id: 'phase-1-phase-2', // source: 'phase-1', // target: 'phase-2', // }, // { // id: 'norm-3-phase-1', // source: 'norm-3', // target: 'phase-1', // }, // { // id: 'phase-2-phase-3', // source: 'phase-2', // target: 'phase-3', // }, // { // id: 'norm-2-phase-3', // source: 'norm-2', // target: 'phase-3', // }, // { // id: 'norm-2-phase-2', // source: 'norm-2', // target: 'phase-2', // }, // { // id: 'phase-3-end', // source: 'phase-3', // target: 'end', // } // ] // }; // const onlyStartEnd : FlowState = { // name: "onlyStartEnd", // nodes: [ // { // id: 'start', // type: 'start', // position: {x: 0, y: 0}, // data: {label: 'start'} // }, // { // id: 'end', // type: 'end', // position: {x: 0, y: 300}, // data: {label: 'End'} // } // ], // edges:[ // { // id: 'start-end', // source: 'start', // target: 'end', // }, // ] // }; // // states that contain invalid programs for testing if correct errors are thrown: // const phaseConnectsToInvalidNodeType : FlowState = { // name: "phaseConnectsToInvalidNodeType", // nodes: [ // { // id: 'start', // type: 'start', // position: {x: 0, y: 0}, // data: {label: 'start'} // }, // { // id: 'phase-1', // type: 'phase', // position: {x: 0, y: 150}, // data: {label: 'Generic Phase', number: 1}, // }, // { // id: 'default-1', // type: 'default', // position: {x: 0, y: 150}, // data: {label: 'Generic Norm'}, // }, // { // id: 'end', // type: 'end', // position: {x: 0, y: 300}, // data: {label: 'End'} // } // ], // edges:[ // { // id: 'start-phase-1', // source: 'start', // target: 'phase-1', // }, // { // id: 'phase-1-default-1', // source: 'phase-1', // target: 'default-1', // }, // ] // }; // const phaseHasNoOutgoingConnections : FlowState = { // name: "phaseHasNoOutgoingConnections", // nodes: [ // { // id: 'start', // type: 'start', // position: {x: 0, y: 0}, // data: {label: 'start'} // }, // { // id: 'phase-1', // type: 'phase', // position: {x: 0, y: 150}, // data: {label: 'Generic Phase', number: 1}, // }, // { // id: 'phase-2', // type: 'phase', // position: {x: 0, y: 150}, // data: {label: 'Generic Phase', number: 2}, // }, // { // id: 'end', // type: 'end', // position: {x: 0, y: 300}, // data: {label: 'End'} // } // ], // edges:[ // { // id: 'start-phase-1', // source: 'start', // target: 'phase-1', // }, // ] // }; // const phaseHasTooManyOutgoingConnections : FlowState = { // name: "phaseHasTooManyOutgoingConnections", // nodes: [ // { // id: 'start', // type: 'start', // position: {x: 0, y: 0}, // data: {label: 'start'} // }, // { // id: 'phase-1', // type: 'phase', // position: {x: 0, y: 150}, // data: {label: 'Generic Phase', number: 1}, // }, // { // id: 'phase-2', // type: 'phase', // position: {x: 0, y: 150}, // data: {label: 'Generic Phase', number: 2}, // }, // { // id: 'end', // type: 'end', // position: {x: 0, y: 300}, // data: {label: 'End'} // } // ], // edges:[ // { // id: 'start-phase-1', // source: 'start', // target: 'phase-1', // }, // { // id: 'phase-1-phase-2', // source: 'phase-1', // target: 'phase-2', // }, // { // id: 'phase-1-end', // source: 'phase-1', // target: 'end', // }, // { // id: 'phase-2-end', // source: 'phase-2', // target: 'end', // }, // ] // }; // describe('Graph Reducer Tests', () => { // describe('defaultGraphPreprocessor', () => { // test.each([ // { // state: onlyOnePhase, // expected: [ // { // phaseNode: { // id: 'phase-1', // type: 'phase', // position: {x: 0, y: 150}, // data: {label: 'Generic Phase', number: 1}, // }, // nextPhaseId: 'end', // connectedNorms: [], // connectedGoals: [], // }] // }, // { // state: onlyThreePhases, // expected: [ // { // phaseNode: { // id: 'phase-1', // type: 'phase', // position: {x: 0, y: 150}, // data: {label: 'Generic Phase', number: 1}, // }, // nextPhaseId: 'phase-2', // connectedNorms: [], // connectedGoals: [], // }, // { // phaseNode: { // id: 'phase-2', // type: 'phase', // position: {x: 0, y: 150}, // data: {label: 'Generic Phase', number: 2}, // }, // nextPhaseId: 'phase-3', // connectedNorms: [], // connectedGoals: [], // }, // { // phaseNode: { // id: 'phase-3', // type: 'phase', // position: {x: 0, y: 150}, // data: {label: 'Generic Phase', number: 3}, // }, // nextPhaseId: 'end', // connectedNorms: [], // connectedGoals: [], // }] // }, // { // state: onlySingleEdgeNorms, // expected: [ // { // phaseNode: { // id: 'phase-1', // type: 'phase', // position: {x: 0, y: 150}, // data: {label: 'Generic Phase', number: 1}, // }, // nextPhaseId: 'phase-2', // connectedNorms: [], // connectedGoals: [], // }, // { // phaseNode: { // id: 'phase-2', // type: 'phase', // position: {x: 0, y: 150}, // data: {label: 'Generic Phase', number: 2}, // }, // nextPhaseId: 'phase-3', // connectedNorms: [{ // id: 'norm-1', // type: 'norm', // position: {x: 0, y: 150}, // data: {label: 'Generic Norm', value: "generic"}, // }], // connectedGoals: [], // }, // { // phaseNode: { // id: 'phase-3', // type: 'phase', // position: {x: 0, y: 150}, // data: {label: 'Generic Phase', number: 3}, // }, // nextPhaseId: 'end', // connectedNorms: [{ // id: 'norm-2', // type: 'norm', // position: {x: 0, y: 150}, // data: {label: 'Generic Norm', value: "generic"}, // }], // connectedGoals: [], // }] // }, // { // state: multiEdgeNorms, // expected: [ // { // phaseNode: { // id: 'phase-1', // type: 'phase', // position: {x: 0, y: 150}, // data: {label: 'Generic Phase', number: 1}, // }, // nextPhaseId: 'phase-2', // connectedNorms: [{ // id: 'norm-3', // type: 'norm', // position: {x: 0, y: 150}, // data: {label: 'Generic Norm', value: "generic"}, // }], // connectedGoals: [], // }, // { // phaseNode: { // id: 'phase-2', // type: 'phase', // position: {x: 0, y: 150}, // data: {label: 'Generic Phase', number: 2}, // }, // nextPhaseId: 'phase-3', // connectedNorms: [{ // id: 'norm-1', // type: 'norm', // position: {x: 0, y: 150}, // data: {label: 'Generic Norm', value: "generic"}, // }, // { // id: 'norm-2', // type: 'norm', // position: {x: 0, y: 150}, // data: {label: 'Generic Norm', value: "generic"}, // }], // connectedGoals: [], // }, // { // phaseNode: { // id: 'phase-3', // type: 'phase', // position: {x: 0, y: 150}, // data: {label: 'Generic Phase', number: 3}, // }, // nextPhaseId: 'end', // connectedNorms: [{ // id: 'norm-1', // type: 'norm', // position: {x: 0, y: 150}, // data: {label: 'Generic Norm', value: "generic"}, // }, // { // id: 'norm-2', // type: 'norm', // position: {x: 0, y: 150}, // data: {label: 'Generic Norm', value: "generic"}, // }], // connectedGoals: [], // }] // }, // { // state: onlyStartEnd, // expected: [], // } // ])(`tests state: $state.name`, ({state, expected}) => { // const output = defaultGraphPreprocessor(state.nodes, state.edges); // expect(output).toEqual(expected); // }); // }); // describe("orderPhases", () => { // test.each([ // { // state: onlyOnePhase, // expected: { // phaseNodes: [{ // id: 'phase-1', // type: 'phase', // position: {x: 0, y: 150}, // data: {label: 'Generic Phase', number: 1}, // }], // connections: new Map([["phase-1","end"]]) // } // }, // { // state: onlyThreePhases, // expected: { // phaseNodes: [ // { // id: 'phase-1', // type: 'phase', // position: {x: 0, y: 150}, // data: {label: 'Generic Phase', number: 1}, // }, // { // id: 'phase-2', // type: 'phase', // position: {x: 0, y: 150}, // data: {label: 'Generic Phase', number: 2}, // }, // { // id: 'phase-3', // type: 'phase', // position: {x: 0, y: 150}, // data: {label: 'Generic Phase', number: 3}, // }], // connections: new Map([ // ["phase-1","phase-2"], // ["phase-2","phase-3"], // ["phase-3","end"] // ]) // } // }, // { // state: onlySingleEdgeNorms, // expected: { // phaseNodes: [ // { // id: 'phase-1', // type: 'phase', // position: {x: 0, y: 150}, // data: {label: 'Generic Phase', number: 1}, // }, // { // id: 'phase-2', // type: 'phase', // position: {x: 0, y: 150}, // data: {label: 'Generic Phase', number: 2}, // }, // { // id: 'phase-3', // type: 'phase', // position: {x: 0, y: 150}, // data: {label: 'Generic Phase', number: 3}, // }], // connections: new Map([ // ["phase-1","phase-2"], // ["phase-2","phase-3"], // ["phase-3","end"] // ]) // } // }, // { // state: onlyStartEnd, // expected: { // phaseNodes: [], // connections: new Map() // } // } // ])(`tests state: $state.name`, ({state, expected}) => { // const output = orderPhases(state.nodes, state.edges); // expect(output.phaseNodes).toEqual(expected.phaseNodes); // expect(output.connections).toEqual(expected.connections); // }); // test.each([ // { // state: phaseConnectsToInvalidNodeType, // expected: new Error('| INVALID PROGRAM | the node "default-1" that "phase-1" connects to is not a phase or end node') // }, // { // state: phaseHasNoOutgoingConnections, // expected: new Error('| INVALID PROGRAM | the source handle of "phase-1" doesn\'t have any outgoing connections') // }, // { // state: phaseHasTooManyOutgoingConnections, // expected: new Error('| INVALID PROGRAM | the source handle of "phase-1" connects to too many targets') // } // ])(`tests erroneous state: $state.name`, ({state, expected}) => { // const testForError = () => { // orderPhases(state.nodes, state.edges); // }; // expect(testForError).toThrow(expected); // }) // }) // describe("defaultPhaseReducer", () => { // test("phaseReducer handles empty norms and goals without failing", () => { // const input : PreparedPhase = { // phaseNode: { // id: 'phase-1', // type: 'phase', // position: {x: 0, y: 150}, // data: {label: 'Generic Phase', number: 1}, // }, // nextPhaseId: 'end', // connectedNorms: [], // connectedGoals: [], // } // const output = defaultPhaseReducer(input); // expect(output).toEqual({ // id: 'phase-1', // name: 'Generic Phase', // nextPhaseId: 'end', // phaseData: { // norms: [], // goals: [] // } // }); // }); // test("defaultNormReducer reduces norms correctly", () => { // const input : PreparedPhase = { // phaseNode: { // id: 'phase-1', // type: 'phase', // position: {x: 0, y: 150}, // data: {label: 'Generic Phase', number: 1}, // }, // nextPhaseId: 'end', // connectedNorms: [{ // id: 'norm-1', // type: 'norm', // position: {x: 0, y: 150}, // data: {label: 'Generic Norm', value: "generic"}, // }], // connectedGoals: [], // } // const output = defaultPhaseReducer(input); // expect(output).toEqual({ // id: 'phase-1', // name: 'Generic Phase', // nextPhaseId: 'end', // phaseData: { // norms: [{ // id: 'norm-1', // name: 'Generic Norm', // value: "generic" // }], // goals: [] // } // }); // }); // test("defaultGoalReducer reduces goals correctly", () => { // const input : PreparedPhase = { // phaseNode: { // id: 'phase-1', // type: 'phase', // position: {x: 0, y: 150}, // data: {label: 'Generic Phase', number: 1}, // }, // nextPhaseId: 'end', // connectedNorms: [], // connectedGoals: [{ // id: 'goal-1', // type: 'goal', // position: {x: 0, y: 150}, // data: {label: 'Generic Goal', value: "generic"}, // }], // } // const output = defaultPhaseReducer(input); // expect(output).toEqual({ // id: 'phase-1', // name: 'Generic Phase', // nextPhaseId: 'end', // phaseData: { // norms: [], // goals: [{ // id: 'goal-1', // name: 'Generic Goal', // value: "generic" // }] // } // }); // }); // }) // describe("GraphReducer", () => { // test.each([ // { // state: onlyOnePhase, // expected: [ // { // id: 'phase-1', // name: 'Generic Phase', // nextPhaseId: 'end', // phaseData: { // norms: [], // goals: [] // } // }] // }, // { // state: onlyThreePhases, // expected: [ // { // id: 'phase-1', // name: 'Generic Phase', // nextPhaseId: 'phase-2', // phaseData: { // norms: [], // goals: [] // } // }, // { // id: 'phase-2', // name: 'Generic Phase', // nextPhaseId: 'phase-3', // phaseData: { // norms: [], // goals: [] // } // }, // { // id: 'phase-3', // name: 'Generic Phase', // nextPhaseId: 'end', // phaseData: { // norms: [], // goals: [] // } // }] // }, // { // state: onlySingleEdgeNorms, // expected: [ // { // id: 'phase-1', // name: 'Generic Phase', // nextPhaseId: 'phase-2', // phaseData: { // norms: [], // goals: [] // } // }, // { // id: 'phase-2', // name: 'Generic Phase', // nextPhaseId: 'phase-3', // phaseData: { // norms: [ // { // id: 'norm-1', // name: 'Generic Norm', // value: "generic" // } // ], // goals: [] // } // }, // { // id: 'phase-3', // name: 'Generic Phase', // nextPhaseId: 'end', // phaseData: { // norms: [{ // id: 'norm-2', // name: 'Generic Norm', // value: "generic" // }], // goals: [] // } // }] // }, // { // state: multiEdgeNorms, // expected: [ // { // id: 'phase-1', // name: 'Generic Phase', // nextPhaseId: 'phase-2', // phaseData: { // norms: [{ // id: 'norm-3', // name: 'Generic Norm', // value: "generic" // }], // goals: [] // } // }, // { // id: 'phase-2', // name: 'Generic Phase', // nextPhaseId: 'phase-3', // phaseData: { // norms: [ // { // id: 'norm-1', // name: 'Generic Norm', // value: "generic" // }, // { // id: 'norm-2', // name: 'Generic Norm', // value: "generic" // } // ], // goals: [] // } // }, // { // id: 'phase-3', // name: 'Generic Phase', // nextPhaseId: 'end', // phaseData: { // norms: [{ // id: 'norm-1', // name: 'Generic Norm', // value: "generic" // }, // { // id: 'norm-2', // name: 'Generic Norm', // value: "generic" // }], // goals: [] // } // }] // }, // { // state: onlyStartEnd, // expected: [], // } // ])(`tests state: $state.name`, ({state, expected}) => { // useFlowStore.setState({nodes: state.nodes, edges: state.edges}); // const output = graphReducer(); // uses default reducers // expect(output).toEqual(expected); // }) // // we run the test for correct error handling for the entire graph reducer as well, // // to make sure no errors occur before we intend to handle the errors ourselves // test.each([ // { // state: phaseConnectsToInvalidNodeType, // expected: new Error('| INVALID PROGRAM | the node "default-1" that "phase-1" connects to is not a phase or end node') // }, // { // state: phaseHasNoOutgoingConnections, // expected: new Error('| INVALID PROGRAM | the source handle of "phase-1" doesn\'t have any outgoing connections') // }, // { // state: phaseHasTooManyOutgoingConnections, // expected: new Error('| INVALID PROGRAM | the source handle of "phase-1" connects to too many targets') // } // ])(`tests erroneous state: $state.name`, ({state, expected}) => { // useFlowStore.setState({nodes: state.nodes, edges: state.edges}); // const testForError = () => { // graphReducer(); // }; // expect(testForError).toThrow(expected); // }) // }) // });