Skip to content

Commit fbf8232

Browse files
committed
feat: enhance SmartEdge stories with new scenarios and add storyPlayHelpers for improved testing
1 parent 198cd0f commit fbf8232

3 files changed

Lines changed: 631 additions & 113 deletions

File tree

src/stories/SmartEdge.stories.tsx

Lines changed: 215 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -1,125 +1,227 @@
1-
import { expect, userEvent, waitFor } from "storybook/test";
21
import { demoRegistry } from "../demos/registry";
32
import { GraphWrapper } from "../demos/GraphWrapper";
4-
import type { Meta, StoryFn } from "@storybook/react-vite";
5-
import type { DemoGraphProps } from "../demos/registry";
6-
7-
export default {
3+
import {
4+
demoStoryPlay,
5+
dragSmartConnectionPreview,
6+
expectBezierCurves,
7+
expectCustomLabelButtons,
8+
expectDemoGraph,
9+
expectEdgePaths,
10+
expectPathAvoidsRect,
11+
expectStraightOrStepPaths,
12+
interactWithEditableEdge,
13+
} from "./storyPlayHelpers";
14+
import { demoAvoidAreas } from "../demos/DummyData";
15+
import type { Meta, StoryObj } from "@storybook/react-vite";
16+
17+
const meta = {
818
title: "Smart Edge",
919
component: GraphWrapper,
1020
parameters: {
1121
layout: "fullscreen",
1222
},
13-
} as Meta;
23+
} satisfies Meta<typeof GraphWrapper>;
24+
25+
export default meta;
26+
27+
type Story = StoryObj<typeof meta>;
28+
29+
export const SmartBezier: Story = {
30+
args: demoRegistry.smartBezier,
31+
play: demoStoryPlay(async (canvasElement) => {
32+
await expectDemoGraph(canvasElement, {
33+
nodeCount: { exact: 7 },
34+
edgeCount: { exact: 9 },
35+
});
36+
await expectBezierCurves(canvasElement);
37+
}),
38+
};
39+
40+
export const SmartStraight: Story = {
41+
args: demoRegistry.smartStraight,
42+
play: demoStoryPlay(async (canvasElement) => {
43+
await expectDemoGraph(canvasElement, {
44+
nodeCount: { exact: 7 },
45+
edgeCount: { exact: 9 },
46+
});
47+
await expectStraightOrStepPaths(canvasElement);
48+
}),
49+
};
50+
51+
export const SmartStep: Story = {
52+
args: demoRegistry.smartStep,
53+
play: demoStoryPlay(async (canvasElement) => {
54+
await expectDemoGraph(canvasElement, {
55+
nodeCount: { exact: 7 },
56+
edgeCount: { exact: 9 },
57+
});
58+
await expectStraightOrStepPaths(canvasElement);
59+
}),
60+
};
61+
62+
export const SmartStepConfigured: Story = {
63+
args: demoRegistry.smartStepConfigured,
64+
play: demoStoryPlay(async (canvasElement) => {
65+
await expectDemoGraph(canvasElement, {
66+
nodeCount: { exact: 7 },
67+
edgeCount: { exact: 9 },
68+
});
69+
await expectStraightOrStepPaths(canvasElement);
70+
}),
71+
};
72+
73+
export const SmartSmoothStep: Story = {
74+
args: demoRegistry.smartSmoothStep,
75+
play: demoStoryPlay(async (canvasElement) => {
76+
await expectDemoGraph(canvasElement, {
77+
nodeCount: { exact: 7 },
78+
edgeCount: { exact: 9 },
79+
});
80+
await expectEdgePaths(canvasElement, { exact: 9 });
81+
}),
82+
};
83+
84+
export const SmartSmoothStepConfigured: Story = {
85+
args: demoRegistry.smartSmoothStepConfigured,
86+
play: demoStoryPlay(async (canvasElement) => {
87+
await expectDemoGraph(canvasElement, {
88+
nodeCount: { exact: 7 },
89+
edgeCount: { exact: 9 },
90+
});
91+
await expectEdgePaths(canvasElement, { exact: 9 });
92+
}),
93+
};
94+
95+
export const SmartBezierWithCustomLabel: Story = {
96+
args: demoRegistry.smartBezierWithCustomLabel,
97+
play: demoStoryPlay(async (canvasElement) => {
98+
await expectDemoGraph(canvasElement, {
99+
nodeCount: { exact: 7 },
100+
edgeCount: { exact: 9 },
101+
});
102+
await expectCustomLabelButtons(canvasElement, { exact: 9 });
103+
}),
104+
};
14105

15-
const Template: StoryFn<DemoGraphProps> = (args) => <GraphWrapper {...args} />;
106+
export const SmartBezierSimple: Story = {
107+
args: demoRegistry.smartBezierSimple,
108+
play: demoStoryPlay(async (canvasElement) => {
109+
await expectDemoGraph(canvasElement, {
110+
nodeCount: { exact: 2 },
111+
edgeCount: { exact: 1 },
112+
});
113+
await expectBezierCurves(canvasElement);
114+
}),
115+
};
16116

17-
export const SmartBezier = Template.bind({});
18-
SmartBezier.args = demoRegistry.smartBezier;
117+
export const SmartStepUnaligned: Story = {
118+
args: demoRegistry.smartStepUnaligned,
119+
play: demoStoryPlay(async (canvasElement) => {
120+
await expectDemoGraph(canvasElement, {
121+
nodeCount: { exact: 4 },
122+
edgeCount: { exact: 3 },
123+
});
124+
await expectStraightOrStepPaths(canvasElement);
125+
}),
126+
};
19127

20-
export const SmartStraight = Template.bind({});
21-
SmartStraight.args = demoRegistry.smartStraight;
128+
export const SmartStepHorizontal: Story = {
129+
args: demoRegistry.smartStepHorizontal,
130+
play: demoStoryPlay(async (canvasElement) => {
131+
await expectDemoGraph(canvasElement, {
132+
nodeCount: { exact: 3 },
133+
edgeCount: { exact: 2 },
134+
});
135+
await expectStraightOrStepPaths(canvasElement);
136+
}),
137+
};
138+
139+
export const SmartBezierSubFlow: Story = {
140+
args: demoRegistry.smartBezierSubFlow,
141+
play: demoStoryPlay(async (canvasElement) => {
142+
await expectDemoGraph(canvasElement, {
143+
nodeCount: { exact: 8 },
144+
edgeCount: { exact: 7 },
145+
});
146+
await expectBezierCurves(canvasElement);
147+
}),
148+
};
149+
150+
export const SmartStepSubFlow: Story = {
151+
args: demoRegistry.smartStepSubFlow,
152+
play: demoStoryPlay(async (canvasElement) => {
153+
await expectDemoGraph(canvasElement, {
154+
nodeCount: { exact: 8 },
155+
edgeCount: { exact: 7 },
156+
});
157+
await expectStraightOrStepPaths(canvasElement);
158+
}),
159+
};
160+
161+
export const SmartBezierSubFlowGroup: Story = {
162+
args: demoRegistry.smartBezierSubFlowGroup,
163+
play: demoStoryPlay(async (canvasElement) => {
164+
await expectDemoGraph(canvasElement, {
165+
nodeCount: { exact: 8 },
166+
edgeCount: { exact: 5 },
167+
});
168+
await expectBezierCurves(canvasElement);
169+
}),
170+
};
171+
172+
export const SmartStepSubFlowGroup: Story = {
173+
args: demoRegistry.smartStepSubFlowGroup,
174+
play: demoStoryPlay(async (canvasElement) => {
175+
await expectDemoGraph(canvasElement, {
176+
nodeCount: { exact: 8 },
177+
edgeCount: { exact: 5 },
178+
});
179+
await expectStraightOrStepPaths(canvasElement);
180+
}),
181+
};
182+
183+
export const SmartFloating: Story = {
184+
args: demoRegistry.smartFloating,
185+
play: demoStoryPlay(async (canvasElement) => {
186+
await expectDemoGraph(canvasElement, {
187+
nodeCount: { exact: 7 },
188+
edgeCount: { exact: 6 },
189+
});
190+
await expectBezierCurves(canvasElement);
191+
}),
192+
};
193+
194+
export const SmartFloatingWithConnectionLine: Story = {
195+
args: demoRegistry.smartFloatingWithConnectionLine,
196+
play: demoStoryPlay(async (canvasElement) => {
197+
await expectDemoGraph(canvasElement, {
198+
nodeCount: { exact: 7 },
199+
edgeCount: { exact: 6 },
200+
});
201+
await dragSmartConnectionPreview(canvasElement, "f-hub");
202+
}),
203+
};
204+
205+
export const SmartBezierWithAvoidArea: Story = {
206+
args: demoRegistry.smartBezierWithAvoidArea,
207+
play: demoStoryPlay(async (canvasElement) => {
208+
await expectDemoGraph(canvasElement, {
209+
nodeCount: { exact: 2 },
210+
edgeCount: { exact: 1 },
211+
});
212+
213+
const [avoidArea] = demoAvoidAreas;
214+
await expectPathAvoidsRect(canvasElement, avoidArea);
215+
}),
216+
};
22217

23-
export const SmartStep = Template.bind({});
24-
SmartStep.args = demoRegistry.smartStep;
25-
26-
export const SmartStepConfigured = Template.bind({});
27-
SmartStepConfigured.args = demoRegistry.smartStepConfigured;
28-
29-
export const SmartSmoothStep = Template.bind({});
30-
SmartSmoothStep.args = demoRegistry.smartSmoothStep;
31-
32-
export const SmartSmoothStepConfigured = Template.bind({});
33-
SmartSmoothStepConfigured.args = demoRegistry.smartSmoothStepConfigured;
34-
35-
export const SmartBezierWithCustomLabel = Template.bind({});
36-
SmartBezierWithCustomLabel.args = demoRegistry.smartBezierWithCustomLabel;
37-
38-
export const SmartBezierSimple = Template.bind({});
39-
SmartBezierSimple.args = demoRegistry.smartBezierSimple;
40-
41-
export const SmartStepUnaligned = Template.bind({});
42-
SmartStepUnaligned.args = demoRegistry.smartStepUnaligned;
43-
44-
export const SmartStepHorizontal = Template.bind({});
45-
SmartStepHorizontal.args = demoRegistry.smartStepHorizontal;
46-
47-
export const SmartBezierSubFlow = Template.bind({});
48-
SmartBezierSubFlow.args = demoRegistry.smartBezierSubFlow;
49-
50-
export const SmartStepSubFlow = Template.bind({});
51-
SmartStepSubFlow.args = demoRegistry.smartStepSubFlow;
52-
53-
export const SmartBezierSubFlowGroup = Template.bind({});
54-
SmartBezierSubFlowGroup.args = demoRegistry.smartBezierSubFlowGroup;
55-
56-
export const SmartStepSubFlowGroup = Template.bind({});
57-
SmartStepSubFlowGroup.args = demoRegistry.smartStepSubFlowGroup;
58-
59-
export const SmartFloating = Template.bind({});
60-
SmartFloating.args = demoRegistry.smartFloating;
61-
62-
export const SmartFloatingWithConnectionLine = Template.bind({});
63-
SmartFloatingWithConnectionLine.args =
64-
demoRegistry.smartFloatingWithConnectionLine;
65-
66-
export const SmartBezierWithAvoidArea = Template.bind({});
67-
SmartBezierWithAvoidArea.args = demoRegistry.smartBezierWithAvoidArea;
68-
SmartBezierWithAvoidArea.play = async ({ canvasElement }) => {
69-
const edgePath = await waitFor(() => {
70-
const path = canvasElement.querySelector<SVGPathElement>(
71-
".react-flow__edge-path",
72-
);
73-
if (!path) throw new Error("edge path not rendered yet");
74-
return path;
75-
});
76-
await expect(edgePath.getAttribute("d")).toBeTruthy();
77-
};
78-
79-
export const SmartEditable = Template.bind({});
80-
SmartEditable.args = demoRegistry.smartEditable;
81-
SmartEditable.play = async ({ canvasElement }) => {
82-
const controlPoints = await waitFor(() => {
83-
const circles = canvasElement.querySelectorAll<SVGCircleElement>(
84-
"[data-testid='smart-edge-control-point']",
85-
);
86-
if (circles.length === 0) throw new Error("control points not rendered");
87-
return circles;
88-
});
89-
90-
await expect(controlPoints.length).toBeGreaterThanOrEqual(3);
91-
92-
const activePoint = canvasElement.querySelector<SVGCircleElement>(
93-
"circle.active[data-testid='smart-edge-control-point']",
94-
);
95-
if (!activePoint) throw new Error("active control point not found");
96-
97-
const edgePath = canvasElement.querySelector<SVGPathElement>(
98-
".react-flow__edge-path",
99-
);
100-
if (!edgePath) throw new Error("edge path not rendered");
101-
const initialPath = edgePath.getAttribute("d");
102-
103-
await userEvent.click(activePoint);
104-
await userEvent.keyboard("{ArrowRight}{ArrowRight}{ArrowRight}");
105-
106-
await waitFor(() => {
107-
const path = canvasElement.querySelector<SVGPathElement>(
108-
".react-flow__edge-path",
109-
);
110-
if (!path) throw new Error("edge path not rendered");
111-
if (path.getAttribute("d") === initialPath) {
112-
throw new Error("edge path did not change after moving the waypoint");
113-
}
114-
});
115-
116-
const inactivePoint = canvasElement.querySelector<SVGCircleElement>(
117-
"[data-testid='smart-edge-control-point']:not(.active)",
118-
);
119-
if (inactivePoint) {
120-
await userEvent.click(inactivePoint);
121-
}
122-
123-
activePoint.focus();
124-
await userEvent.keyboard("{Delete}");
218+
export const SmartEditable: Story = {
219+
args: demoRegistry.smartEditable,
220+
play: demoStoryPlay(async (canvasElement) => {
221+
await expectDemoGraph(canvasElement, {
222+
nodeCount: { exact: 6 },
223+
edgeCount: { exact: 1 },
224+
});
225+
await interactWithEditableEdge(canvasElement);
226+
}),
125227
};

0 commit comments

Comments
 (0)