diff --git a/lib/react/PipelineStagesTable.tsx b/lib/react/PipelineStagesTable.tsx index 5f6342d..b899eb2 100644 --- a/lib/react/PipelineStagesTable.tsx +++ b/lib/react/PipelineStagesTable.tsx @@ -61,6 +61,9 @@ const getStageStatus = ( } if (stepIndex === currentIndex) { + if (solver.failed) { + return "Failed" + } if (solver.activeSubSolver) { if (solver.activeSubSolver.failed) { return "Failed" diff --git a/tests/failed-pipeline-stage.test.ts b/tests/failed-pipeline-stage.test.ts new file mode 100644 index 0000000..7275613 --- /dev/null +++ b/tests/failed-pipeline-stage.test.ts @@ -0,0 +1,66 @@ +import { expect, test } from "bun:test" +import { BasePipelineSolver } from "../lib/BasePipelineSolver" +import { BaseSolver } from "../lib/BaseSolver" +import { getDisplayedStages } from "../lib/react/PipelineStagesTable" + +class FailingSolver extends BaseSolver { + override _step() { + this.failed = true + this.error = "No route found" + } +} + +class FailurePipeline extends BasePipelineSolver { + pipelineDef = [ + { + solverName: "route", + solverClass: FailingSolver, + getConstructorParams: () => [], + }, + { + solverName: "next", + solverClass: BaseSolver, + getConstructorParams: () => [], + }, + ] +} + +test("a failed pipeline stage remains Failed after the active solver is cleared", () => { + const pipeline = new FailurePipeline(null) + pipeline.solve() + + expect(pipeline.failed).toBe(true) + expect(pipeline.activeSubSolver).toBeNull() + expect(getDisplayedStages(pipeline).map((stage) => stage.status)).toEqual([ + "Failed", + "Not Started", + ]) +}) + +test("a stage that fails during construction is displayed as Failed", () => { + class InvalidSolver extends BaseSolver { + constructor() { + super() + throw new Error("Invalid input") + } + } + class InvalidPipeline extends BasePipelineSolver { + pipelineDef = [ + { + solverName: "invalid", + solverClass: InvalidSolver, + getConstructorParams: () => [], + }, + ] + } + const pipeline = new InvalidPipeline(null) + expect(() => pipeline.step()).toThrow("Invalid input") + expect(getDisplayedStages(pipeline)[0]?.status).toBe("Failed") +}) + +test("a stage transitions from Not Started to In Progress before failure", () => { + const pipeline = new FailurePipeline(null) + expect(getDisplayedStages(pipeline)[0]?.status).toBe("Not Started") + pipeline.step() + expect(getDisplayedStages(pipeline)[0]?.status).toBe("In Progress") +})