From 2ecb33dcde88733bff681022c5b8712e94a3772c Mon Sep 17 00:00:00 2001 From: JobvAlewijk Date: Tue, 6 Jan 2026 15:19:49 +0100 Subject: [PATCH] chore: now actually runs tests --- src/pages/VisProgPage/VisProg.tsx | 8 +- .../simpleProgram/SimpleProgram.test.tsx | 176 ++++++++++++++++++ test/pages/simpleProgram/SimpleProgram.tsx | 83 --------- 3 files changed, 180 insertions(+), 87 deletions(-) create mode 100644 test/pages/simpleProgram/SimpleProgram.test.tsx delete mode 100644 test/pages/simpleProgram/SimpleProgram.tsx diff --git a/src/pages/VisProgPage/VisProg.tsx b/src/pages/VisProgPage/VisProg.tsx index 3db9a00..5311feb 100644 --- a/src/pages/VisProgPage/VisProg.tsx +++ b/src/pages/VisProgPage/VisProg.tsx @@ -140,7 +140,7 @@ function VisualProgrammingUI() { } // currently outputs the prepared program to the console -function runProgramm() { +function runProgram() { const phases = graphReducer(); const program = {phases} console.log(JSON.stringify(program, null, 2)); @@ -183,11 +183,11 @@ function VisProgPage() { const [showSimpleProgram, setShowSimpleProgram] = useState(false); const setProgramState = useProgramStore((state) => state.setProgramState); - const runProgram = () => { + const onClick = () => { const phases = graphReducer(); // reduce graph setProgramState({ phases }); // <-- save to store setShowSimpleProgram(true); // show SimpleProgram - runProgramm(); // send to backend if needed + runProgram(); // send to backend if needed }; if (showSimpleProgram) { @@ -204,7 +204,7 @@ function VisProgPage() { return ( <> - + ) } diff --git a/test/pages/simpleProgram/SimpleProgram.test.tsx b/test/pages/simpleProgram/SimpleProgram.test.tsx new file mode 100644 index 0000000..dcb56ba --- /dev/null +++ b/test/pages/simpleProgram/SimpleProgram.test.tsx @@ -0,0 +1,176 @@ +import { render, screen, fireEvent } from "@testing-library/react"; +import SimpleProgram from "../../../src/pages/SimpleProgram/SimpleProgram"; +import useProgramStore from "../../../src/utils/programStore"; + +/** + * Helper to preload the program store before rendering. + */ +function loadProgram(phases: Record[]) { + useProgramStore.getState().setProgramState({ phases }); +} + +describe("SimpleProgram", () => { + beforeEach(() => { + loadProgram([]); + }); + + test("shows empty state when no program is loaded", () => { + render(); + expect(screen.getByText("No program loaded.")).toBeInTheDocument(); + }); + + test("renders first phase content", () => { + loadProgram([ + { + id: "phase-1", + norms: [{ id: "n1", norm: "Be polite" }], + goals: [{ id: "g1", description: "Finish task", achieved: true }], + triggers: [{ id: "t1", label: "Keyword trigger" }], + }, + ]); + + render(); + + expect(screen.getByText("Phase 1 / 1")).toBeInTheDocument(); + expect(screen.getByText("Be polite")).toBeInTheDocument(); + expect(screen.getByText("Finish task")).toBeInTheDocument(); + expect(screen.getByText("Keyword trigger")).toBeInTheDocument(); + }); + + test("renders empty messages when phase has no data", () => { + loadProgram([ + { + id: "phase-1", + norms: [], + goals: [], + triggers: [], + }, + ]); + + render(); + + expect(screen.getAllByText("No norms defined.").length).toBeGreaterThanOrEqual(1); + expect(screen.getAllByText("No goals defined.").length).toBeGreaterThanOrEqual(1); + expect(screen.getAllByText("No triggers defined.").length).toBeGreaterThanOrEqual(1); + expect( + screen.getByText("No conditional norms defined.") + ).toBeInTheDocument(); + }); + + test("allows navigating between phases", () => { + loadProgram([ + { + id: "phase-1", + norms: [], + goals: [], + triggers: [], + }, + { + id: "phase-2", + norms: [{ id: "n2", norm: "Be careful" }], + goals: [], + triggers: [], + }, + ]); + + render(); + + expect(screen.getByText("Phase 1 / 2")).toBeInTheDocument(); + + fireEvent.click(screen.getByText("Next ▶")); + + expect(screen.getByText("Phase 2 / 2")).toBeInTheDocument(); + expect(screen.getByText("Be careful")).toBeInTheDocument(); + }); + + test("prev button is disabled on first phase", () => { + loadProgram([{ id: "phase-1", norms: [], goals: [], triggers: [] }]); + + render(); + expect(screen.getByText("◀ Prev")).toBeDisabled(); + }); + + test("next button is disabled on last phase", () => { + loadProgram([{ id: "phase-1", norms: [], goals: [], triggers: [] }]); + + render(); + expect(screen.getByText("Next ▶")).toBeDisabled(); + }); + + test("prev and next buttons enable/disable correctly when navigating", () => { + loadProgram([ + { id: "p1", norms: [], goals: [], triggers: [] }, + { id: "p2", norms: [], goals: [], triggers: [] }, + ]); + + render(); + + const prev = screen.getByText("◀ Prev"); + const next = screen.getByText("Next ▶"); + + expect(prev).toBeDisabled(); + expect(next).not.toBeDisabled(); + + fireEvent.click(next); + + expect(prev).not.toBeDisabled(); + expect(next).toBeDisabled(); + }); + + test("renders achieved and unachieved goals with correct icons", () => { + loadProgram([ + { + id: "phase-1", + norms: [], + goals: [ + { id: "g1", description: "Done goal", achieved: true }, + { id: "g2", description: "Failed goal", achieved: false }, + ], + triggers: [], + }, + ]); + + render(); + + expect(screen.getByText("✔")).toBeInTheDocument(); + expect(screen.getByText("✖")).toBeInTheDocument(); + expect(screen.getByText("Done goal")).toBeInTheDocument(); + expect(screen.getByText("Failed goal")).toBeInTheDocument(); + }); + + test("renders fallback labels when optional fields are missing", () => { + loadProgram([ + { + id: "phase-1", + norms: [{}], + goals: [{}], + triggers: [{}], + }, + ]); + + render(); + + expect(screen.getByText("Unnamed norm")).toBeInTheDocument(); + expect(screen.getByText("Unnamed goal")).toBeInTheDocument(); + expect(screen.getByText("Unnamed trigger")).toBeInTheDocument(); + }); + + test("does not crash when navigating beyond boundaries", () => { + loadProgram([ + { id: "p1", norms: [], goals: [], triggers: [] }, + { id: "p2", norms: [], goals: [], triggers: [] }, + ]); + + render(); + + fireEvent.click(screen.getByText("Next ▶")); + fireEvent.click(screen.getByText("Next ▶")); + + expect(screen.getByText("Phase 2 / 2")).toBeInTheDocument(); + + fireEvent.click(screen.getByText("◀ Prev")); + fireEvent.click(screen.getByText("◀ Prev")); + + expect(screen.getByText("Phase 1 / 2")).toBeInTheDocument(); + }); +}); diff --git a/test/pages/simpleProgram/SimpleProgram.tsx b/test/pages/simpleProgram/SimpleProgram.tsx deleted file mode 100644 index 22fcbbf..0000000 --- a/test/pages/simpleProgram/SimpleProgram.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import { render, screen, fireEvent } from "@testing-library/react"; -import SimpleProgram from "../../../src/pages/SimpleProgram/SimpleProgram"; -import useProgramStore from "../../../src/utils/programStore"; - -/** - * Helper to preload the program store before rendering. - */ -function loadProgram(phases: Record[]) { - useProgramStore.getState().setProgramState({ phases }); -} - -describe("SimpleProgram", () => { - beforeEach(() => { - loadProgram([]); - }); - - test("shows empty state when no program is loaded", () => { - render(); - expect(screen.getByText("No program loaded.")).toBeInTheDocument(); - }); - - test("renders first phase content", () => { - loadProgram([ - { - id: "phase-1", - norms: [{ id: "n1", norm: "Be polite" }], - goals: [{ id: "g1", description: "Finish task", achieved: true }], - triggers: [{ id: "t1", label: "Keyword trigger" }], - }, - ]); - - render(); - - expect(screen.getByText("Phase 1 / 1")).toBeInTheDocument(); - expect(screen.getByText("Be polite")).toBeInTheDocument(); - expect(screen.getByText("Finish task")).toBeInTheDocument(); - expect(screen.getByText("Keyword trigger")).toBeInTheDocument(); - }); - - test("allows navigating between phases", () => { - loadProgram([ - { - id: "phase-1", - norms: [], - goals: [], - triggers: [], - }, - { - id: "phase-2", - norms: [{ id: "n2", norm: "Be careful" }], - goals: [], - triggers: [], - }, - ]); - - render(); - - expect(screen.getByText("Phase 1 / 2")).toBeInTheDocument(); - - fireEvent.click(screen.getByText("Next ▶")); - - expect(screen.getByText("Phase 2 / 2")).toBeInTheDocument(); - expect(screen.getByText("Be careful")).toBeInTheDocument(); - }); - - test("prev button is disabled on first phase", () => { - loadProgram([ - { id: "phase-1", norms: [], goals: [], triggers: [] }, - ]); - - render(); - expect(screen.getByText("◀ Prev")).toBeDisabled(); - }); - - test("next button is disabled on last phase", () => { - loadProgram([ - { id: "phase-1", norms: [], goals: [], triggers: [] }, - ]); - - render(); - expect(screen.getByText("Next ▶")).toBeDisabled(); - }); -});