Files
fusion/packages/dashboard/app/components/__tests__/WorkflowAddStepModal.test.tsx
gsxdsm 4679c4960f Address PR review feedback (#2006)
- fix: fragments are hidden in the add-step dialog when the target edge is
  inside a foreach/loop/optional-group (they expand to top-level subgraphs
  and cannot splice into a template-child edge), and
  spliceInsertedSubgraphOnEdge now refuses container-internal edges as a
  second line of defense (Greptile P1 x2).
- test: add-step modal container-target hiding, multi-entry/exit splice
  fan-out, internal-cycle entries fallback, ambiguous merge-inbound
  lifecycle fallback, and edge-targeted "as optional group" wiring
  (CodeRabbit nitpicks).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 18:06:22 -07:00

73 lines
2.8 KiB
TypeScript

import { render, screen, cleanup } from "@testing-library/react";
import { describe, expect, it, vi, afterEach } from "vitest";
import { MessageSquare, Repeat } from "lucide-react";
import type { WorkflowDefinition, WorkflowStepTemplate } from "@fusion/core";
import { WorkflowAddStepModal, type AddStepPaletteEntry } from "../WorkflowAddStepModal";
/*
FNXC:WorkflowSimpleView 2026-07-12-14:30:
PR #2006 review coverage: when the add-step dialog targets an edge INSIDE a
container (disallowContainers), it must hide container palette kinds,
fragments (top-level subgraphs cannot splice into a template-child edge),
and the "as optional group" template variant — while keeping plain step
templates, which materialize a single sibling-safe node.
*/
const palette: AddStepPaletteEntry[] = [
{ kind: "prompt", label: "Prompt", icon: MessageSquare },
{ kind: "loop", label: "Loop", icon: Repeat },
];
const fragment = {
id: "WF-FRAG",
kind: "fragment",
name: "Lint fragment",
description: "",
ir: { version: "v1", name: "Lint fragment", nodes: [], edges: [] },
layout: {},
createdAt: "2026-06-03T00:00:00.000Z",
updatedAt: "2026-06-03T00:00:00.000Z",
} as WorkflowDefinition;
const stepTemplate = { id: "tpl-1", name: "Security review" } as WorkflowStepTemplate;
function renderModal(disallowContainers: boolean) {
return render(
<WorkflowAddStepModal
open
onClose={() => {}}
palette={palette}
disallowContainers={disallowContainers}
fragments={[fragment]}
stepTemplates={[stepTemplate]}
pluginTemplates={[]}
onPickPalette={vi.fn()}
onPickFragment={vi.fn()}
onPickStepTemplate={vi.fn()}
onPickStepTemplateAsOptionalGroup={vi.fn()}
/>,
);
}
describe("WorkflowAddStepModal", () => {
afterEach(() => cleanup());
it("offers containers, fragments, and optional-group inserts for top-level targets", () => {
renderModal(false);
expect(screen.getByTestId("wf-add-step-loop-loop")).toBeInTheDocument();
expect(screen.getByTestId("wf-add-step-fragment-WF-FRAG")).toBeInTheDocument();
expect(screen.getByTestId("wf-add-step-tpl-tpl-1")).toBeInTheDocument();
expect(screen.getByTestId("wf-add-step-tpl-tpl-1-optional-group")).toBeInTheDocument();
});
it("hides containers, fragments, and optional-group inserts for container-internal targets", () => {
renderModal(true);
expect(screen.getByTestId("wf-add-step-prompt-prompt")).toBeInTheDocument();
expect(screen.queryByTestId("wf-add-step-loop-loop")).not.toBeInTheDocument();
expect(screen.queryByTestId("wf-add-step-fragment-WF-FRAG")).not.toBeInTheDocument();
// Plain step templates remain — they insert a single sibling-safe node.
expect(screen.getByTestId("wf-add-step-tpl-tpl-1")).toBeInTheDocument();
expect(screen.queryByTestId("wf-add-step-tpl-tpl-1-optional-group")).not.toBeInTheDocument();
});
});