diff --git a/editor.planx.uk/src/@planx/graph/__tests__/formatOps.test.ts b/editor.planx.uk/src/@planx/graph/__tests__/formatOps.test.ts new file mode 100644 index 0000000000..da63f1a4b3 --- /dev/null +++ b/editor.planx.uk/src/@planx/graph/__tests__/formatOps.test.ts @@ -0,0 +1,269 @@ +import { formatOps,Graph } from "../index"; + +describe("Update operations", () => { + test("Updating a single property of a node", () => { + const ops = [ + { + p: ["FW5G3EMBI3", "data", "text"], + oi: "Which vegetables?", + od: "Which fruits?", + }, + ]; + + expect(formatOps(flowWithChecklist, ops)).toEqual([ + 'Updated Checklist text from "Which fruits?" to "Which vegetables?"', + ]); + }); + + test("Updating many properties of a node", () => { + const ops = [ + { + p: ["FW5G3EMBI3", "data", "fn"], + oi: "fruit", + }, + { + p: ["WDwUTbF7Gq", "data", "val"], + oi: "berry.blue", + }, + { + p: ["xTBfSd1Tjy", "data", "val"], + oi: "banana", + }, + ]; + + expect(formatOps(flowWithChecklist, ops)).toEqual([ + 'Added Checklist fn "fruit"', + 'Added Answer val "berry.blue"', + 'Added Answer val "banana"', + ]); + }); +}); + +describe("Insert operations", () => { + test("Adding a new node to the graph", () => { + const ops = [ + { + p: ["_root", "edges", 0], + li: "ubCTG9OtFw", + }, + { + p: ["ubCTG9OtFw"], + oi: { + type: 8, + data: { + title: "This is a test", + color: "#c81bcb", + resetButton: false, + }, + }, + }, + ]; + + expect(formatOps(emptyFlow, ops)).toEqual([ + 'Added Notice "This is a test"', + ]); + }); + + test("Adding a new node and its' children to the graph", () => { + const ops = [ + { + p: ["_root", "edges", 0], + li: "FW5G3EMBI3", + }, + { + p: ["FW5G3EMBI3"], + oi: { + type: 105, + data: { + allRequired: false, + text: "Which fruits?", + }, + edges: ["WDwUTbF7Gq", "SO5XbLwSYp", "xTBfSd1Tjy"], + }, + }, + { + p: ["WDwUTbF7Gq"], + oi: { + data: { + text: "Blueberry", + }, + type: 200, + }, + }, + { + p: ["SO5XbLwSYp"], + oi: { + data: { + text: "Orange", + }, + type: 200, + }, + }, + { + p: ["xTBfSd1Tjy"], + oi: { + data: { + text: "Banana", + }, + type: 200, + }, + }, + ]; + + expect(formatOps(emptyFlow, ops)).toEqual([ + 'Added Checklist "Which fruits?"', + 'Added Answer "Blueberry"', + 'Added Answer "Orange"', + 'Added Answer "Banana"', + ]); + }); + + test("Adding a new child and data property to an existing node", () => { + const ops = [ + { + p: ["FW5G3EMBI3", "data", "description"], + oi: "

Fruits contain seeds and come from the flower of a plant

", + }, + { + p: ["FW5G3EMBI3", "edges"], + oi: ["WDwUTbF7Gq", "SO5XbLwSYp", "xTBfSd1Tjy", "zzQAMXexRj"], + od: ["WDwUTbF7Gq", "SO5XbLwSYp", "xTBfSd1Tjy"], + }, + { + p: ["zzQAMXexRj"], + oi: { + data: { + text: "Strawberry", + }, + type: 200, + }, + }, + ]; + + expect(formatOps(flowWithChecklist, ops)).toEqual([ + 'Added Checklist description "

Fruits contain seeds and come from the flower of a plant

"', + "Updated order of Checklist edges", + 'Added Answer "Strawberry"', + ]); + }); +}); + +describe("Delete operations", () => { + test("Deleting a node from the graph", () => { + const ops = [ + { + p: ["_root", "edges", 1], + ld: "FW5G3EMBI3", + }, + { + p: ["WDwUTbF7Gq"], + od: { + data: { + text: "Blueberry", + }, + type: 200, + }, + }, + { + p: ["SO5XbLwSYp"], + od: { + data: { + text: "Orange", + }, + type: 200, + }, + }, + { + p: ["xTBfSd1Tjy"], + od: { + data: { + text: "Banana", + }, + type: 200, + }, + }, + { + p: ["FW5G3EMBI3"], + od: { + type: 105, + data: { + allRequired: false, + text: "Which fruits?", + }, + edges: ["wBwRtMce7c", "SO5XbLwSYp", "xTBfSd1Tjy"], + }, + }, + ]; + + expect(formatOps(flowWithChecklist, ops)).toEqual([ + 'Deleted Answer "Blueberry"', + 'Deleted Answer "Orange"', + 'Deleted Answer "Banana"', + 'Deleted Checklist "Which fruits?"', + ]); + }); + + test("Deleting a child of a node", () => { + const ops = [ + { + p: ["FW5G3EMBI3", "edges"], + oi: ["WDwUTbF7Gq", "xTBfSd1Tjy"], + od: ["WDwUTbF7Gq", "SO5XbLwSYp", "xTBfSd1Tjy"], + }, + { + p: ["SO5XbLwSYp"], + od: { + data: { + text: "Orange", + }, + type: 200, + }, + }, + ]; + + expect(formatOps(flowWithChecklist, ops)).toEqual([ + "Updated order of Checklist edges", + 'Deleted Answer "Orange"', + ]); + }); + + test.todo("Deleting a data property of an existing node"); +}); + +const emptyFlow: Graph = { + _root: { + edges: [], + }, +}; + +const flowWithChecklist: Graph = { + _root: { + edges: ["FW5G3EMBI3"], + }, + FW5G3EMBI3: { + type: 105, + data: { + allRequired: false, + text: "Which fruits?", + }, + edges: ["WDwUTbF7Gq", "SO5XbLwSYp", "xTBfSd1Tjy"], + }, + WDwUTbF7Gq: { + data: { + text: "Blueberry", + }, + type: 200, + }, + SO5XbLwSYp: { + data: { + text: "Orange", + }, + type: 200, + }, + xTBfSd1Tjy: { + data: { + text: "Banana", + }, + type: 200, + }, +}; diff --git a/editor.planx.uk/src/@planx/graph/index.ts b/editor.planx.uk/src/@planx/graph/index.ts index e58b997c43..86f14585ba 100644 --- a/editor.planx.uk/src/@planx/graph/index.ts +++ b/editor.planx.uk/src/@planx/graph/index.ts @@ -6,7 +6,6 @@ import trim from "lodash/trim"; import zip from "lodash/zip"; import { customAlphabet } from "nanoid-good"; import en from "nanoid-good/locale/en"; -import { TYPE } from "react-toastify/dist/utils"; import { ImmerJSONPatch, OT } from "./types"; @@ -532,7 +531,9 @@ export const formatOps = (graph: Graph, ops: any[]): string[] => { ); } } else if (op.p.includes("edges")) { - output.push(`Updated order of nodes`); + output.push( + `Updated order of ${node.type ? TYPES[node.type] : "graph"} edges`, + ); } // Adding (inserting) an object or its properties } else if (Object.keys(op).includes("oi")) { @@ -559,7 +560,9 @@ export const formatOps = (graph: Graph, ops: any[]): string[] => { } else if (Object.keys(op).includes("od")) { if (op.od.type) { output.push( - `Deleted ${TYPES} "${op.od.data?.title || op.od.data?.text}"`, + `Deleted ${TYPES[op.od.type]} "${ + op.od.data?.title || op.od.data?.text + }"`, ); } else if (op.p.includes("data")) { if (node.type) { @@ -574,13 +577,13 @@ export const formatOps = (graph: Graph, ops: any[]): string[] => { output.push(`Deleted node from branch`); } } - // Updating the _root list (update = list insert + list delete) + // Updating the _root list (update = list insert or list delete) } else if ( Object.keys(op).includes("li") && Object.keys(op).includes("ld") ) { if (op.p.includes("edges") && op.p.includes("_root")) { - output.push(`Re-ordered _root nodes`); + output.push(`Re-ordered the graph`); } } });