33.3 KB1007 lines
Blame
1import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts';
2
3describe('Graph', () => {
4 it('1: should render a simple flowchart no htmlLabels', () => {
5 imgSnapshotTest(
6 `graph TD
7 A[Christmas] -->|Get money| B(Go shopping)
8 B --> C{Let me think}
9 C -->|One| D[Laptop]
10 C -->|Two| E[iPhone]
11 C -->|Three| F[fa:fa-car Car]
12 `,
13 { flowchart: { htmlLabels: false }, fontFamily: 'courier' }
14 );
15 });
16
17 it('2: should render a simple flowchart with htmlLabels', () => {
18 imgSnapshotTest(
19 `graph TD
20 A[Christmas] -->|Get money| B(Go shopping)
21 B --> C{Let me think}
22 C -->|One| D[Laptop]
23 C -->|Two| E[iPhone]
24 C -->|Three| F[fa:fa-car Car]
25 `,
26 { flowchart: { htmlLabels: true }, fontFamily: 'courier' }
27 );
28 });
29
30 it('3: should render a simple flowchart with line breaks', () => {
31 imgSnapshotTest(
32 `
33 graph TD
34 A[Christmas] -->|Get money| B(Go shopping)
35 B --> C{Let me thinksssss<br/>ssssssssssssssssssssss<br/>sssssssssssssssssssssssssss}
36 C -->|One| D[Laptop]
37 C -->|Two| E[iPhone]
38 C -->|Three| F[Car]
39 `,
40 { fontFamily: 'courier' }
41 );
42 });
43
44 it('4: should render a simple flowchart with trapezoid and inverse trapezoid vertex options.', () => {
45 imgSnapshotTest(
46 `
47 graph TD
48 A[/Christmas\\]
49 A -->|Get money| B[\\Go shopping/]
50 B --> C{Let me thinksssss<br/>ssssssssssssssssssssss<br/>sssssssssssssssssssssssssss}
51 C -->|One| D[/Laptop/]
52 C -->|Two| E[\\iPhone\\]
53 C -->|Three| F[Car]
54 `,
55 { fontFamily: 'courier' }
56 );
57 });
58
59 it('5: should style nodes via a class.', () => {
60 imgSnapshotTest(
61 `
62 graph TD
63 1A --> 1B
64 1B --> 1C
65 1C --> D
66 1C --> E
67
68 classDef processHead fill:#888888,color:white,font-weight:bold,stroke-width:3px,stroke:#001f3f
69 class 1A,1B,D,E processHead
70 `,
71 { fontFamily: 'courier' }
72 );
73 });
74
75 it('6: should render a flowchart full of circles', () => {
76 imgSnapshotTest(
77 `
78 graph LR
79 47(SAM.CommonFA.FMESummary)-->48(SAM.CommonFA.CommonFAFinanceBudget)
80 37(SAM.CommonFA.BudgetSubserviceLineVolume)-->48(SAM.CommonFA.CommonFAFinanceBudget)
81 35(SAM.CommonFA.PopulationFME)-->47(SAM.CommonFA.FMESummary)
82 41(SAM.CommonFA.MetricCost)-->47(SAM.CommonFA.FMESummary)
83 44(SAM.CommonFA.MetricOutliers)-->47(SAM.CommonFA.FMESummary)
84 46(SAM.CommonFA.MetricOpportunity)-->47(SAM.CommonFA.FMESummary)
85 40(SAM.CommonFA.OPVisits)-->47(SAM.CommonFA.FMESummary)
86 38(SAM.CommonFA.CommonFAFinanceRefund)-->47(SAM.CommonFA.FMESummary)
87 43(SAM.CommonFA.CommonFAFinancePicuDays)-->47(SAM.CommonFA.FMESummary)
88 42(SAM.CommonFA.CommonFAFinanceNurseryDays)-->47(SAM.CommonFA.FMESummary)
89 45(SAM.CommonFA.MetricPreOpportunity)-->46(SAM.CommonFA.MetricOpportunity)
90 35(SAM.CommonFA.PopulationFME)-->45(SAM.CommonFA.MetricPreOpportunity)
91 41(SAM.CommonFA.MetricCost)-->45(SAM.CommonFA.MetricPreOpportunity)
92 41(SAM.CommonFA.MetricCost)-->44(SAM.CommonFA.MetricOutliers)
93 39(SAM.CommonFA.ChargeDetails)-->43(SAM.CommonFA.CommonFAFinancePicuDays)
94 39(SAM.CommonFA.ChargeDetails)-->42(SAM.CommonFA.CommonFAFinanceNurseryDays)
95 39(SAM.CommonFA.ChargeDetails)-->41(SAM.CommonFA.MetricCost)
96 39(SAM.CommonFA.ChargeDetails)-->40(SAM.CommonFA.OPVisits)
97 35(SAM.CommonFA.PopulationFME)-->39(SAM.CommonFA.ChargeDetails)
98 36(SAM.CommonFA.PremetricCost)-->39(SAM.CommonFA.ChargeDetails)
99 `,
100 { fontFamily: 'courier' }
101 );
102 });
103
104 it('7: should render a flowchart full of icons', () => {
105 imgSnapshotTest(
106 `
107 graph TD
108 9e122290_1ec3_e711_8c5a_005056ad0002("fa:fa-creative-commons My System | Test Environment")
109 82072290_1ec3_e711_8c5a_005056ad0002("fa:fa-cogs Shared Business Logic Server:Service 1")
110 db052290_1ec3_e711_8c5a_005056ad0002("fa:fa-cogs Shared Business Logic Server:Service 2")
111 4e112290_1ec3_e711_8c5a_005056ad0002("fa:fa-cogs Shared Report Server:Service 1")
112 30122290_1ec3_e711_8c5a_005056ad0002("fa:fa-cogs Shared Report Server:Service 2")
113 5e112290_1ec3_e711_8c5a_005056ad0002("fa:fa-cogs Dedicated Test Business Logic Server:Service 1")
114 c1112290_1ec3_e711_8c5a_005056ad0002("fa:fa-cogs Dedicated Test Business Logic Server:Service 2")
115 b7042290_1ec3_e711_8c5a_005056ad0002("fa:fa-circle [DBServer\\SharedDbInstance].[SupportDb]")
116 8f102290_1ec3_e711_8c5a_005056ad0002("fa:fa-circle [DBServer\\SharedDbInstance].[DevelopmentDb]")
117 0e102290_1ec3_e711_8c5a_005056ad0002("fa:fa-circle [DBServer\\SharedDbInstance].[TestDb]")
118 07132290_1ec3_e711_8c5a_005056ad0002("fa:fa-circle [DBServer\\SharedDbInstance].[SharedReportingDb]")
119 c7072290_1ec3_e711_8c5a_005056ad0002("fa:fa-server Shared Business Logic Server")
120 ca122290_1ec3_e711_8c5a_005056ad0002("fa:fa-server Shared Report Server")
121 68102290_1ec3_e711_8c5a_005056ad0002("fa:fa-server Dedicated Test Business Logic Server")
122 f4112290_1ec3_e711_8c5a_005056ad0002("fa:fa-database [DBServer\\SharedDbInstance]")
123 d6072290_1ec3_e711_8c5a_005056ad0002("fa:fa-server DBServer")
124 71082290_1ec3_e711_8c5a_005056ad0002("fa:fa-cogs DBServer\\:MSSQLSERVER")
125 c0102290_1ec3_e711_8c5a_005056ad0002("fa:fa-cogs DBServer\\:SQLAgent")
126 9a072290_1ec3_e711_8c5a_005056ad0002("fa:fa-cogs DBServer\\:SQLBrowser")
127 1d0a2290_1ec3_e711_8c5a_005056ad0002("fa:fa-server VmHost1")
128 200a2290_1ec3_e711_8c5a_005056ad0002("fa:fa-server VmHost2")
129 1c0a2290_1ec3_e711_8c5a_005056ad0002("fa:fa-server VmHost3")
130 9e122290_1ec3_e711_8c5a_005056ad0002-->82072290_1ec3_e711_8c5a_005056ad0002
131 9e122290_1ec3_e711_8c5a_005056ad0002-->db052290_1ec3_e711_8c5a_005056ad0002
132 9e122290_1ec3_e711_8c5a_005056ad0002-->4e112290_1ec3_e711_8c5a_005056ad0002
133 9e122290_1ec3_e711_8c5a_005056ad0002-->30122290_1ec3_e711_8c5a_005056ad0002
134 9e122290_1ec3_e711_8c5a_005056ad0002-->5e112290_1ec3_e711_8c5a_005056ad0002
135 9e122290_1ec3_e711_8c5a_005056ad0002-->c1112290_1ec3_e711_8c5a_005056ad0002
136 82072290_1ec3_e711_8c5a_005056ad0002-->b7042290_1ec3_e711_8c5a_005056ad0002
137 82072290_1ec3_e711_8c5a_005056ad0002-->8f102290_1ec3_e711_8c5a_005056ad0002
138 82072290_1ec3_e711_8c5a_005056ad0002-->0e102290_1ec3_e711_8c5a_005056ad0002
139 82072290_1ec3_e711_8c5a_005056ad0002-->c7072290_1ec3_e711_8c5a_005056ad0002
140 db052290_1ec3_e711_8c5a_005056ad0002-->c7072290_1ec3_e711_8c5a_005056ad0002
141 db052290_1ec3_e711_8c5a_005056ad0002-->82072290_1ec3_e711_8c5a_005056ad0002
142 4e112290_1ec3_e711_8c5a_005056ad0002-->b7042290_1ec3_e711_8c5a_005056ad0002
143 4e112290_1ec3_e711_8c5a_005056ad0002-->8f102290_1ec3_e711_8c5a_005056ad0002
144 4e112290_1ec3_e711_8c5a_005056ad0002-->0e102290_1ec3_e711_8c5a_005056ad0002
145 4e112290_1ec3_e711_8c5a_005056ad0002-->07132290_1ec3_e711_8c5a_005056ad0002
146 4e112290_1ec3_e711_8c5a_005056ad0002-->ca122290_1ec3_e711_8c5a_005056ad0002
147 30122290_1ec3_e711_8c5a_005056ad0002-->ca122290_1ec3_e711_8c5a_005056ad0002
148 30122290_1ec3_e711_8c5a_005056ad0002-->4e112290_1ec3_e711_8c5a_005056ad0002
149 5e112290_1ec3_e711_8c5a_005056ad0002-->8f102290_1ec3_e711_8c5a_005056ad0002
150 5e112290_1ec3_e711_8c5a_005056ad0002-->68102290_1ec3_e711_8c5a_005056ad0002
151 c1112290_1ec3_e711_8c5a_005056ad0002-->68102290_1ec3_e711_8c5a_005056ad0002
152 c1112290_1ec3_e711_8c5a_005056ad0002-->5e112290_1ec3_e711_8c5a_005056ad0002
153 b7042290_1ec3_e711_8c5a_005056ad0002-->f4112290_1ec3_e711_8c5a_005056ad0002
154 8f102290_1ec3_e711_8c5a_005056ad0002-->f4112290_1ec3_e711_8c5a_005056ad0002
155 0e102290_1ec3_e711_8c5a_005056ad0002-->f4112290_1ec3_e711_8c5a_005056ad0002
156 07132290_1ec3_e711_8c5a_005056ad0002-->f4112290_1ec3_e711_8c5a_005056ad0002
157 c7072290_1ec3_e711_8c5a_005056ad0002-->1d0a2290_1ec3_e711_8c5a_005056ad0002
158 ca122290_1ec3_e711_8c5a_005056ad0002-->200a2290_1ec3_e711_8c5a_005056ad0002
159 68102290_1ec3_e711_8c5a_005056ad0002-->1c0a2290_1ec3_e711_8c5a_005056ad0002
160 f4112290_1ec3_e711_8c5a_005056ad0002-->d6072290_1ec3_e711_8c5a_005056ad0002
161 f4112290_1ec3_e711_8c5a_005056ad0002-->71082290_1ec3_e711_8c5a_005056ad0002
162 f4112290_1ec3_e711_8c5a_005056ad0002-->c0102290_1ec3_e711_8c5a_005056ad0002
163 f4112290_1ec3_e711_8c5a_005056ad0002-->9a072290_1ec3_e711_8c5a_005056ad0002
164 d6072290_1ec3_e711_8c5a_005056ad0002-->1c0a2290_1ec3_e711_8c5a_005056ad0002
165 71082290_1ec3_e711_8c5a_005056ad0002-->d6072290_1ec3_e711_8c5a_005056ad0002
166 c0102290_1ec3_e711_8c5a_005056ad0002-->d6072290_1ec3_e711_8c5a_005056ad0002
167 c0102290_1ec3_e711_8c5a_005056ad0002-->71082290_1ec3_e711_8c5a_005056ad0002
168 9a072290_1ec3_e711_8c5a_005056ad0002-->d6072290_1ec3_e711_8c5a_005056ad0002
169 9a072290_1ec3_e711_8c5a_005056ad0002-->71082290_1ec3_e711_8c5a_005056ad0002
170 `,
171 { fontFamily: 'courier' }
172 );
173 });
174
175 it('8: should render labels with numbers at the start', () => {
176 imgSnapshotTest(
177 `
178 graph TB;subgraph "number as labels";1;end;
179 `,
180 { fontFamily: 'courier' }
181 );
182 });
183
184 it('9: should render subgraphs', () => {
185 imgSnapshotTest(
186 `
187 graph TB
188 subgraph One
189 a1-->a2
190 end
191 `,
192 { fontFamily: 'courier' }
193 );
194 });
195
196 it('10: should render subgraphs with a title starting with a digit', () => {
197 imgSnapshotTest(
198 `
199 graph TB
200 subgraph 2Two
201 a1-->a2
202 end
203 `,
204 { fontFamily: 'courier' }
205 );
206 });
207
208 it('11: should render styled subgraphs', () => {
209 imgSnapshotTest(
210 `
211 graph TB
212 A
213 B
214 subgraph foo[Foo SubGraph]
215 C
216 D
217 end
218 subgraph bar[Bar SubGraph]
219 E
220 F
221 end
222 G
223
224 A-->B
225 B-->C
226 C-->D
227 B-->D
228 D-->E
229 E-->A
230 E-->F
231 F-->D
232 F-->G
233 B-->G
234 G-->D
235
236 style foo fill:#F99,stroke-width:2px,stroke:#F0F,color:darkred
237 style bar fill:#999,stroke-width:10px,stroke:#0F0,color:blue
238 `,
239 { fontFamily: 'courier' }
240 );
241 });
242
243 it('12: should render a flowchart with long names and class definitions', () => {
244 imgSnapshotTest(
245 `graph LR
246 sid-B3655226-6C29-4D00-B685-3D5C734DC7E1["
247
248 提交申请
249 熊大
250 "];
251 class sid-B3655226-6C29-4D00-B685-3D5C734DC7E1 node-executed;
252 sid-4DA958A0-26D9-4D47-93A7-70F39FD7D51A["
253 负责人审批
254 强子
255 "];
256 class sid-4DA958A0-26D9-4D47-93A7-70F39FD7D51A node-executed;
257 sid-E27C0367-E6D6-497F-9736-3CDC21FDE221["
258 DBA审批
259 强子
260 "];
261 class sid-E27C0367-E6D6-497F-9736-3CDC21FDE221 node-executed;
262 sid-BED98281-9585-4D1B-934E-BD1AC6AC0EFD["
263 SA审批
264 阿美
265 "];
266 class sid-BED98281-9585-4D1B-934E-BD1AC6AC0EFD node-executed;
267 sid-7CE72B24-E0C1-46D3-8132-8BA66BE05AA7["
268 主管审批
269 光头强
270 "];
271 class sid-7CE72B24-E0C1-46D3-8132-8BA66BE05AA7 node-executed;
272 sid-A1B3CD96-7697-4D7C-BEAA-73D187B1BE89["
273 DBA确认
274 强子
275 "];
276 class sid-A1B3CD96-7697-4D7C-BEAA-73D187B1BE89 node-executed;
277 sid-3E35A7FF-A2F4-4E07-9247-DBF884C81937["
278 SA确认
279 阿美
280 "];
281 class sid-3E35A7FF-A2F4-4E07-9247-DBF884C81937 node-executed;
282 sid-4FC27B48-A6F9-460A-A675-021F5854FE22["
283 结束
284 "];
285 class sid-4FC27B48-A6F9-460A-A675-021F5854FE22 node-executed;
286 sid-19DD9E9F-98C1-44EE-B604-842AFEE76F1E["
287 SA执行1
288 强子
289 "];
290 class sid-19DD9E9F-98C1-44EE-B604-842AFEE76F1E node-executed;
291 sid-6C2120F3-D940-4958-A067-0903DCE879C4["
292 SA执行2
293 强子
294 "];
295 class sid-6C2120F3-D940-4958-A067-0903DCE879C4 node-executed;
296 sid-9180E2A0-5C4B-435F-B42F-0D152470A338["
297 DBA执行1
298 强子
299 "];
300 class sid-9180E2A0-5C4B-435F-B42F-0D152470A338 node-executed;
301 sid-03A2C3AC-5337-48A5-B154-BB3FD0EC8DAD["
302 DBA执行3
303 强子
304 "];
305 class sid-03A2C3AC-5337-48A5-B154-BB3FD0EC8DAD node-executed;
306 sid-D5E1F2F4-306C-47A2-BF74-F66E3D769756["
307 DBA执行2
308 强子
309 "];
310 class sid-D5E1F2F4-306C-47A2-BF74-F66E3D769756 node-executed;
311 sid-8C3F2F1D-F014-4F99-B966-095DC1A2BD93["
312 DBA执行4
313 强子
314 "];
315 class sid-8C3F2F1D-F014-4F99-B966-095DC1A2BD93 node-executed;
316 sid-1897B30A-9C5C-4D5B-B80B-76A038785070["
317 负责人确认
318 梁静茹
319 "];
320 class sid-1897B30A-9C5C-4D5B-B80B-76A038785070 node-executed;
321 sid-B3655226-6C29-4D00-B685-3D5C734DC7E1-->sid-7CE72B24-E0C1-46D3-8132-8BA66BE05AA7;
322 sid-4DA958A0-26D9-4D47-93A7-70F39FD7D51A-->sid-1897B30A-9C5C-4D5B-B80B-76A038785070;
323 sid-E27C0367-E6D6-497F-9736-3CDC21FDE221-->sid-A1B3CD96-7697-4D7C-BEAA-73D187B1BE89;
324 sid-BED98281-9585-4D1B-934E-BD1AC6AC0EFD-->sid-3E35A7FF-A2F4-4E07-9247-DBF884C81937;
325 sid-19DD9E9F-98C1-44EE-B604-842AFEE76F1E-->sid-6C2120F3-D940-4958-A067-0903DCE879C4;
326 sid-9180E2A0-5C4B-435F-B42F-0D152470A338-->sid-D5E1F2F4-306C-47A2-BF74-F66E3D769756;
327 sid-03A2C3AC-5337-48A5-B154-BB3FD0EC8DAD-->sid-8C3F2F1D-F014-4F99-B966-095DC1A2BD93;
328 sid-6C2120F3-D940-4958-A067-0903DCE879C4-->sid-4DA958A0-26D9-4D47-93A7-70F39FD7D51A;
329 sid-1897B30A-9C5C-4D5B-B80B-76A038785070-->sid-4FC27B48-A6F9-460A-A675-021F5854FE22;
330 sid-3E35A7FF-A2F4-4E07-9247-DBF884C81937-->sid-19DD9E9F-98C1-44EE-B604-842AFEE76F1E;
331 sid-A1B3CD96-7697-4D7C-BEAA-73D187B1BE89-->sid-9180E2A0-5C4B-435F-B42F-0D152470A338;
332 sid-A1B3CD96-7697-4D7C-BEAA-73D187B1BE89-->sid-03A2C3AC-5337-48A5-B154-BB3FD0EC8DAD;
333 sid-D5E1F2F4-306C-47A2-BF74-F66E3D769756-->sid-4DA958A0-26D9-4D47-93A7-70F39FD7D51A;
334 sid-8C3F2F1D-F014-4F99-B966-095DC1A2BD93-->sid-4DA958A0-26D9-4D47-93A7-70F39FD7D51A;
335 sid-7CE72B24-E0C1-46D3-8132-8BA66BE05AA7-->sid-BED98281-9585-4D1B-934E-BD1AC6AC0EFD;
336 sid-7CE72B24-E0C1-46D3-8132-8BA66BE05AA7-->sid-E27C0367-E6D6-497F-9736-3CDC21FDE221;
337 sid-3E35A7FF-A2F4-4E07-9247-DBF884C81937-->sid-6C2120F3-D940-4958-A067-0903DCE879C4;
338 sid-7CE72B24-E0C1-46D3-8132-8BA66BE05AA7-->sid-4DA958A0-26D9-4D47-93A7-70F39FD7D51A;
339 sid-7CE72B24-E0C1-46D3-8132-8BA66BE05AA7-->sid-4FC27B48-A6F9-460A-A675-021F5854FE22;
340 `,
341 { fontFamily: 'courier' }
342 );
343 });
344
345 it('13: should render color of styled nodes', () => {
346 imgSnapshotTest(
347 `
348 graph LR
349 foo-->bar
350
351 classDef foo fill:lightblue,color:green,stroke:#FF9E2C,font-weight:bold
352 style foo fill:#F99,stroke-width:2px,stroke:#F0F
353 style bar fill:#999,color: #00ff00, stroke-width:10px,stroke:#0F0
354 `,
355 {
356 listUrl: false,
357 listId: 'color styling',
358 fontFamily: 'courier',
359 logLevel: 0,
360 }
361 );
362 });
363
364 it('14: should render hexagons', () => {
365 imgSnapshotTest(
366 `
367 graph TD
368 A[Christmas] -->|Get money| B(Go shopping)
369 B --> C{{Let me think...<br />Do I want something for work,<br />something to spend every free second with,<br />or something to get around?}}
370 C -->|One| D[Laptop]
371 C -->|Two| E[iPhone]
372 C -->|Three| F[Car]
373 click A "index.html#link-clicked" "link test"
374 click B testClick "click test"
375 classDef someclass fill:#f96;
376 class A someclass;
377 class C someclass;
378 `,
379 {
380 listUrl: false,
381 listId: 'color styling',
382 fontFamily: 'courier',
383 logLevel: 0,
384 }
385 );
386 });
387
388 it('15: should render a simple flowchart with comments', () => {
389 imgSnapshotTest(
390 `graph TD
391 A[Christmas] -->|Get money| B(Go shopping)
392 B --> C{Let me think}
393 %% this is a comment
394 C -->|One| D[Laptop]
395 C -->|Two| E[iPhone]
396 C -->|Three| F[fa:fa-car Car]
397 `,
398 { flowchart: { htmlLabels: false }, fontFamily: 'courier' }
399 );
400 });
401
402 it('16: Render Stadium shape', () => {
403 imgSnapshotTest(
404 ` graph TD
405 A([stadium shape test])
406 A -->|Get money| B([Go shopping])
407 B --> C([Let me think...<br />Do I want something for work,<br />something to spend every free second with,<br />or something to get around?])
408 C -->|One| D([Laptop])
409 C -->|Two| E([iPhone])
410 C -->|Three| F([Car<br/>wroom wroom])
411 click A "index.html#link-clicked" "link test"
412 click B testClick "click test"
413 classDef someclass fill:#f96;
414 class A someclass;
415 class C someclass;
416 `,
417 { flowchart: { htmlLabels: false }, fontFamily: 'courier' }
418 );
419 });
420
421 it('17: Render multiline texts', () => {
422 imgSnapshotTest(
423 `graph LR
424 A1[Multi<br>Line] -->|Multi<br>Line| B1(Multi<br>Line)
425 C1[Multi<br/>Line] -->|Multi<br/>Line| D1(Multi<br/>Line)
426 E1[Multi<br />Line] -->|Multi<br />Line| F1(Multi<br />Line)
427 A2[Multi<br>Line] -->|Multi<br>Line| B2(Multi<br>Line)
428 C2[Multi<br/>Line] -->|Multi<br/>Line| D2(Multi<br/>Line)
429 E2[Multi<br />Line] -->|Multi<br />Line| F2(Multi<br />Line)
430 linkStyle 0 stroke:DarkGray,stroke-width:2px
431 linkStyle 1 stroke:DarkGray,stroke-width:2px
432 linkStyle 2 stroke:DarkGray,stroke-width:2px
433 `,
434 { flowchart: { htmlLabels: false }, fontFamily: 'courier' }
435 );
436 });
437
438 it('18: Chaining of nodes', () => {
439 imgSnapshotTest(
440 `graph LR
441 a --> b --> c
442 `,
443 { flowchart: { htmlLabels: false }, fontFamily: 'courier' }
444 );
445 });
446
447 it('19: Multiple nodes and chaining in one statement', () => {
448 imgSnapshotTest(
449 `graph LR
450 a --> b & c--> d
451 `,
452 { flowchart: { htmlLabels: false }, fontFamily: 'courier' }
453 );
454 });
455
456 it('20: Multiple nodes and chaining in one statement', () => {
457 imgSnapshotTest(
458 `graph TD
459 A[ h ] -- hello --> B[" test "]:::exClass & C --> D;
460 classDef exClass background:#bbb,border:1px solid red;
461 `,
462 { flowchart: { htmlLabels: false }, fontFamily: 'courier' }
463 );
464 });
465
466 it('21: Render cylindrical shape', () => {
467 imgSnapshotTest(
468 `graph LR
469 A[(cylindrical<br />shape<br />test)]
470 A -->|Get money| B1[(Go shopping 1)]
471 A -->|Get money| B2[(Go shopping 2)]
472 A -->|Get money| B3[(Go shopping 3)]
473 C[(Let me think...<br />Do I want something for work,<br />something to spend every free second with,<br />or something to get around?)]
474 B1 --> C
475 B2 --> C
476 B3 --> C
477 C -->|One| D[(Laptop)]
478 C -->|Two| E[(iPhone)]
479 C -->|Three| F[(Car)]
480 click A "index.html#link-clicked" "link test"
481 click B testClick "click test"
482 classDef someclass fill:#f96;
483 class A someclass;`,
484 { flowchart: { htmlLabels: false }, fontFamily: 'courier' }
485 );
486 });
487
488 it('22: Render a simple flowchart with nodeSpacing set to 100', () => {
489 imgSnapshotTest(
490 `graph TD
491 A[Christmas] -->|Get money| B(Go shopping)
492 B --> C{Let me think}
493 %% this is a comment
494 C -->|One| D[Laptop]
495 C -->|Two| E[iPhone]
496 C -->|Three| F[fa:fa-car Car]
497 `,
498 { flowchart: { nodeSpacing: 50 }, fontFamily: 'courier' }
499 );
500 });
501
502 it('23: Render a simple flowchart with rankSpacing set to 100', () => {
503 imgSnapshotTest(
504 `graph TD
505 A[Christmas] -->|Get money| B(Go shopping)
506 B --> C{Let me think}
507 %% this is a comment
508 C -->|One| D[Laptop]
509 C -->|Two| E[iPhone]
510 C -->|Three| F[fa:fa-car Car]
511 `,
512 { flowchart: { rankSpacing: '100' }, fontFamily: 'courier' }
513 );
514 });
515
516 it('24: Keep node label text (if already defined) when a style is applied', () => {
517 imgSnapshotTest(
518 `graph LR
519 A(( )) -->|step 1| B(( ))
520 B(( )) -->|step 2| C(( ))
521 C(( )) -->|step 3| D(( ))
522 linkStyle 1 stroke:greenyellow,stroke-width:2px
523 style C fill:greenyellow,stroke:green,stroke-width:4px
524 `,
525 { flowchart: { htmlLabels: false }, fontFamily: 'courier' }
526 );
527 });
528
529 it('25: Handle link click events (link, anchor, mailto, other protocol, script)', () => {
530 imgSnapshotTest(
531 `graph TB
532 TITLE["Link Click Events<br>(click the nodes below)"]
533 A["link test (open in same tab)"]
534 B["link test (open in new tab)"]
535 C[anchor test]
536 D[mailto test]
537 E[other protocol test]
538 F[script test]
539 TITLE --> A & B & C & D & E & F
540 click A "https://mermaid-js.github.io/mermaid/#/" "link test (open in same tab)"
541 click B "https://mermaid-js.github.io/mermaid/#/" "link test (open in new tab)" _blank
542 click C "#link-clicked"
543 click D "mailto:user@user.user" "mailto test"
544 click E "notes://do-your-thing/id" "other protocol test"
545 click F "javascript:alert('test')" "script test"
546 `,
547 { securityLevel: 'loose', fontFamily: 'courier' }
548 );
549 });
550
551 it('26: Set text color of nodes and links according to styles when html labels are enabled', () => {
552 imgSnapshotTest(
553 `graph LR
554 A[red<br>text] -->|red<br>text| B(blue<br>text)
555 C[/red<br/>text/] -->|blue<br/>text| D{blue<br/>text}
556 E{{default<br />style}} -->|default<br />style| F([default<br />style])
557 linkStyle default color:Sienna;
558 linkStyle 0 color:red;
559 linkStyle 1 stroke:DarkGray,stroke-width:2px,color:#0000ff
560 style A color:red;
561 style B color:blue;
562 style C stroke:#ff0000,fill:#ffcccc,color:#ff0000
563 style D stroke:#0000ff,fill:#ccccff,color:#0000ff
564 click B "index.html#link-clicked" "link test"
565 click D testClick "click test"
566 `,
567 { flowchart: { htmlLabels: true } }
568 );
569 });
570
571 it('27: Set text color of nodes and links according to styles when html labels are disabled', () => {
572 imgSnapshotTest(
573 `graph LR
574 A[red<br>text] -->|red<br>text| B(blue<br>text)
575 C[/red<br/>text/] -->|blue<br/>text| D{blue<br/>text}
576 E{{default<br />style}} -->|default<br />style| F([default<br />style])
577 linkStyle default color:Sienna;
578 linkStyle 0 color:red;
579 linkStyle 1 stroke:DarkGray,stroke-width:2px,color:#0000ff
580 style A color:red;
581 style B color:blue;
582 style C stroke:#ff0000,fill:#ffcccc,color:#ff0000
583 style D stroke:#0000ff,fill:#ccccff,color:#0000ff
584 click B "index.html#link-clicked" "link test"
585 click D testClick "click test"
586 `,
587 { flowchart: { htmlLabels: false }, fontFamily: 'courier' }
588 );
589 });
590
591 it('28: Apply default class to all nodes which do not have another class assigned (htmlLabels enabled)', () => {
592 imgSnapshotTest(
593 `graph TD
594 A[myClass1] --> B[default] & C[default]
595 B[default] & C[default] --> D[myClass2]
596 classDef default stroke-width:2px,fill:none,stroke:silver
597 classDef node color:red
598 classDef myClass1 color:#0000ff
599 classDef myClass2 stroke:#0000ff,fill:#ccccff
600 class A myClass1
601 class D myClass2
602 `,
603 { flowchart: { htmlLabels: true } }
604 );
605 });
606
607 it('29: Apply default class to all nodes which do not have another class assigned (htmlLabels disabled)', () => {
608 imgSnapshotTest(
609 `graph TD
610 A[myClass1] --> B[default] & C[default]
611 B[default] & C[default] --> D[myClass2]
612 classDef default stroke-width:2px,fill:none,stroke:silver
613 classDef node color:red
614 classDef myClass1 color:#0000ff
615 classDef myClass2 stroke:#0000ff,fill:#ccccff
616 class A myClass1
617 class D myClass2
618 `,
619 { flowchart: { htmlLabels: false }, fontFamily: 'courier' }
620 );
621 });
622
623 it('30: Possibility to style text color of nodes and subgraphs as well as apply classes to subgraphs', () => {
624 imgSnapshotTest(
625 `graph LR
626 subgraph id1 [title is set]
627 A-->B
628 end
629 subgraph id2 [title]
630 E
631 end
632
633 B-->C
634
635 subgraph id3
636 C-->D
637 end
638 class id3,id2,A redBg;
639 class id3,A whiteTxt;
640 classDef redBg fill:#622;
641 classDef whiteTxt color: white;
642 `,
643 { flowchart: { htmlLabels: false }, fontFamily: 'courier' }
644 );
645 });
646
647 it('31: should not slice off edges that are to the left of the left-most vertex', () => {
648 imgSnapshotTest(
649 `graph TD
650 work --> sleep
651 sleep --> work
652 eat --> sleep
653 work --> eat
654 `,
655 { flowchart: { htmlLabels: false }, fontFamily: 'courier' }
656 );
657 });
658
659 it('32: Render Subroutine shape', () => {
660 imgSnapshotTest(
661 `graph LR
662 A[[subroutine shape test]]
663 A -->|Get money| B[[Go shopping]]
664 B --> C[[Let me think...<br />Do I want something for work,<br />something to spend every free second with,<br />or something to get around?]]
665 C -->|One| D[[Laptop]]
666 C -->|Two| E[[iPhone]]
667 C -->|Three| F[[Car<br/>wroom wroom]]
668 click A "index.html#link-clicked" "link test"
669 click B testClick "click test"
670 classDef someclass fill:#f96;
671 class A someclass;
672 class C someclass;
673 `,
674 { flowchart: { htmlLabels: false }, fontFamily: 'courier' }
675 );
676 });
677
678 it('33: should render a simple flowchart with diagramPadding set to 0', () => {
679 imgSnapshotTest(
680 `graph TD
681 A[Christmas] -->|Get money| B(Go shopping)
682 B --> C{Let me think}
683 %% this is a comment
684 C -->|One| D[Laptop]
685 C -->|Two| E[iPhone]
686 C -->|Three| F[fa:fa-car Car]
687 `,
688 { flowchart: { diagramPadding: 0 } }
689 );
690 });
691
692 it('34: testing the label width in percy', () => {
693 imgSnapshotTest(
694 `graph TD
695 A[Christmas]
696 `,
697 {}
698 );
699 });
700
701 it('35: should honor minimum edge length as specified by the user', () => {
702 imgSnapshotTest(
703 `graph TD
704 L1 --- L2
705 L2 --- C
706 M1 ---> C
707 R1 .-> R2
708 R2 <.-> C
709 C -->|Label 1| E1
710 C -- Label 2 ---> E2
711 C ----> E3
712 C -----> E4
713 C ======> E5
714 `,
715 {}
716 );
717 });
718 it('36: should render escaped without html labels', () => {
719 imgSnapshotTest(
720 `graph TD
721 a["<strong>Haiya</strong>"]-->b
722 `,
723 { htmlLabels: false, flowchart: { htmlLabels: false } }
724 );
725 });
726 it('37: should render non-escaped with html labels', () => {
727 imgSnapshotTest(
728 `graph TD
729 a["<strong>Haiya</strong>"]-->b
730 `,
731 { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
732 );
733 });
734 it('38: should render a flowchart when useMaxWidth is true (default)', () => {
735 renderGraph(
736 `flowchart TD
737 A[Christmas] -->|Get money| B(Go shopping)
738 B --> C{Let me think}
739 C -->|One| D[Laptop]
740 C -->|Two| E[iPhone]
741 C -->|Three| F[fa:fa-car Car]
742 `,
743 { flowchart: { useMaxWidth: true } }
744 );
745 cy.get('svg').should((svg) => {
746 expect(svg).to.have.attr('width', '100%');
747 // expect(svg).to.have.attr('height');
748 // use within because the absolute value can be slightly different depending on the environment ±10%
749 // const height = parseFloat(svg.attr('height'));
750 // expect(height).to.be.within(446 * 0.95, 446 * 1.05);
751 const style = svg.attr('style');
752 expect(style).to.match(/^max-width: [\d.]+px;$/);
753 const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
754 expect(maxWidthValue).to.be.within(446 * 0.9, 446 * 1.1);
755 });
756 });
757 it('39: should render a flowchart when useMaxWidth is false', () => {
758 renderGraph(
759 `graph TD
760 A[Christmas] -->|Get money| B(Go shopping)
761 B --> C{Let me think}
762 C -->|One| D[Laptop]
763 C -->|Two| E[iPhone]
764 C -->|Three| F[fa:fa-car Car]
765 `,
766 { flowchart: { useMaxWidth: false } }
767 );
768 cy.get('svg').should((svg) => {
769 // const height = parseFloat(svg.attr('height'));
770 const width = parseFloat(svg.attr('width'));
771 // use within because the absolute value can be slightly different depending on the environment ±10%
772 // expect(height).to.be.within(446 * 0.95, 446 * 1.05);
773 expect(width).to.be.within(446 * 0.9, 446 * 1.1);
774 expect(svg).to.not.have.attr('style');
775 });
776 });
777 it('40: should add edge animation', () => {
778 renderGraph(
779 `
780 flowchart TD
781 A(["Start"]) L_A_B_0@--> B{"Decision"}
782 B --> C["Option A"] & D["Option B"]
783 style C stroke-width:4px,stroke-dasharray: 5
784 L_A_B_0@{ animation: slow }
785 L_B_D_0@{ animation: fast }`,
786 { screenshot: false }
787 );
788 // Verify animation classes are applied to both edges
789 cy.get('path#L_A_B_0').should('have.class', 'edge-animation-slow');
790 cy.get('path#L_B_D_0').should('have.class', 'edge-animation-fast');
791 });
792 it('58: handle styling with style expressions', () => {
793 imgSnapshotTest(
794 `
795 graph LR
796 id1(Start)-->id2(Stop)
797 style id1 fill:#f9f,stroke:#333,stroke-width:4px
798 style id2 fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5
799 `,
800 { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
801 );
802 });
803 it('60: handle styling for all node shapes', () => {
804 imgSnapshotTest(
805 `
806 graph LR
807 A[red text] -->|default style| B(blue text)
808 C([red text]) -->|default style| D[[blue text]]
809 E[(red text)] -->|default style| F((blue text))
810 G>red text] -->|default style| H{blue text}
811 I{{red text}} -->|default style| J[/blue text/]
812 linkStyle default color:Sienna;
813 style A stroke:#ff0000,fill:#ffcccc,color:#ff0000
814 style B stroke:#0000ff,fill:#ccccff,color:#0000ff
815 style C stroke:#ff0000,fill:#ffcccc,color:#ff0000
816 style D stroke:#0000ff,fill:#ccccff,color:#0000ff
817 style E stroke:#ff0000,fill:#ffcccc,color:#ff0000
818 style F stroke:#0000ff,fill:#ccccff,color:#0000ff
819 style G stroke:#ff0000,fill:#ffcccc,color:#ff0000
820 style H stroke:#0000ff,fill:#ccccff,color:#0000ff
821 style I stroke:#ff0000,fill:#ffcccc,color:#ff0000
822 style J stroke:#0000ff,fill:#ccccff,color:#0000ff
823 `,
824 { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
825 );
826 });
827 it('61: fontawesome icons in edge labels', () => {
828 imgSnapshotTest(
829 `
830graph TD
831 C -->|fa:fa-car Car| F[fa:fa-car Car]
832 `,
833 { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
834 );
835 });
836 it('62: fontawesome icons in edge labels', () => {
837 imgSnapshotTest(
838 `
839 graph TB
840 subgraph bar[Bar]
841 F
842 end
843 style bar fill:#999,stroke-width:10px,stroke:#0F0,color:blue
844 `,
845 { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
846 );
847 });
848 it('63: fontawesome icons in edge labels', () => {
849 imgSnapshotTest(
850 `
851 graph TB
852 A
853 B
854 subgraph foo[Foo SubGraph]
855 C
856 D
857 end
858 subgraph bar[Bar SubGraph]
859 E
860 F
861 end
862 G
863
864 A-->B
865 B-->C
866 C-->D
867 B-->D
868 D-->E
869 E-->A
870 E-->F
871 F-->D
872 F-->G
873 B-->G
874 G-->D
875
876 style foo fill:#F99,stroke-width:2px,stroke:#F0F,color:darkred
877 style bar fill:#999,stroke-width:10px,stroke:#0F0,color:blue
878 `,
879 { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
880 );
881 });
882 it('64: fontawesome icons in edge labels', () => {
883 imgSnapshotTest(
884 `
885 %%{init:{"theme":"base", "themeVariables": {"primaryColor":"#411d4e", "titleColor":"white", "darkMode":true}}}%%
886 flowchart LR
887 subgraph A
888 a --> b
889 end
890 subgraph B
891 i -->f
892 end
893 A --> B
894 `,
895 { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
896 );
897 });
898 it('65: text-color from classes', () => {
899 imgSnapshotTest(
900 `
901 flowchart LR
902 classDef dark fill:#000,stroke:#000,stroke-width:4px,color:#fff
903 Lorem --> Ipsum --> Dolor
904 class Lorem,Dolor dark
905 `,
906 { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
907 );
908 });
909 it('66: apply class called default on node called default', () => {
910 imgSnapshotTest(
911 `
912 graph TD
913 classDef default fill:#a34,stroke:#000,stroke-width:4px,color:#fff
914 hello --> default
915 `,
916 { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
917 );
918 });
919
920 it('67: should be able to style default node independently', () => {
921 imgSnapshotTest(
922 `
923 flowchart TD
924 classDef default fill:#a34
925 hello --> default
926
927 style default stroke:#000,stroke-width:4px
928 `,
929 {
930 flowchart: { htmlLabels: true },
931 securityLevel: 'loose',
932 }
933 );
934 });
935 it('#6369: edge color should affect arrow head', () => {
936 imgSnapshotTest(
937 `
938 flowchart LR
939 A --> B
940 A --> C
941 C --> D
942
943 linkStyle 0 stroke:#D50000
944 linkStyle 2 stroke:#D50000
945 `,
946 {
947 flowchart: { htmlLabels: true },
948 securityLevel: 'loose',
949 }
950 );
951 });
952 it('68: should honor subgraph direction when inheritDir is false', () => {
953 imgSnapshotTest(
954 `
955 %%{init: {"flowchart": { "inheritDir": false }}}%%
956 flowchart TB
957 direction LR
958 subgraph A
959 direction TB
960 a --> b
961 end
962 subgraph B
963 c --> d
964 end
965 `,
966 {
967 fontFamily: 'courier',
968 }
969 );
970 });
971
972 it('69: should inherit global direction when inheritDir is true', () => {
973 imgSnapshotTest(
974 `
975 %%{init: {"flowchart": { "inheritDir": true }}}%%
976 flowchart TB
977 direction LR
978 subgraph A
979 direction TB
980 a --> b
981 end
982 subgraph B
983 c --> d
984 end
985 `,
986 {
987 fontFamily: 'courier',
988 }
989 );
990 });
991
992 it('70: should render a subgraph with direction TD', () => {
993 imgSnapshotTest(
994 `
995 flowchart LR
996 subgraph A
997 direction TD
998 a --> b
999 end
1000 `,
1001 {
1002 fontFamily: 'courier',
1003 }
1004 );
1005 });
1006});
1007