diff --git a/.changeset/dry-plums-glow.md b/.changeset/dry-plums-glow.md deleted file mode 100644 index e5b95dc3c75..00000000000 --- a/.changeset/dry-plums-glow.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'mermaid': patch ---- - -Fix for issue with calculation of label width when using in firefox diff --git a/.changeset/witty-rabbits-hunt.md b/.changeset/witty-rabbits-hunt.md deleted file mode 100644 index 3817bb92865..00000000000 --- a/.changeset/witty-rabbits-hunt.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'mermaid': patch ---- - -Ban DOMPurify v3.1.7 as a dependency diff --git a/.cspell/code-terms.txt b/.cspell/code-terms.txt index 8e4c02261af..f4862006fe6 100644 --- a/.cspell/code-terms.txt +++ b/.cspell/code-terms.txt @@ -26,6 +26,7 @@ concat controlx controly CSSCLASS +curv CYLINDEREND CYLINDERSTART DAGA diff --git a/.cspell/cspell.config.yaml b/.cspell/cspell.config.yaml index 33d69019365..b16040c8ce3 100644 --- a/.cspell/cspell.config.yaml +++ b/.cspell/cspell.config.yaml @@ -28,6 +28,9 @@ dictionaryDefinitions: - name: suggestions words: - none + - disp + - subproc + - tria suggestWords: - seperator:separator - vertice:vertex diff --git a/.cspell/mermaid-terms.txt b/.cspell/mermaid-terms.txt index 59a3d108fbe..8551bd1962b 100644 --- a/.cspell/mermaid-terms.txt +++ b/.cspell/mermaid-terms.txt @@ -5,6 +5,7 @@ bmatrix braintree catmull compositTitleSize +curv doublecircle elems gantt @@ -24,6 +25,7 @@ multigraph nodesep NOTEGROUP Pinterest +procs rankdir ranksep rect diff --git a/.github/lychee.toml b/.github/lychee.toml index 2e3b08c4137..288ab054a23 100644 --- a/.github/lychee.toml +++ b/.github/lychee.toml @@ -44,7 +44,10 @@ exclude = [ "https://chromewebstore.google.com", # Drupal 403 -"https://(www.)?drupal.org" +"https://(www.)?drupal.org", + +# Swimm returns 404, eventhough the link is valid +"https://docs.swimm.io" ] # Exclude all private IPs from checking. diff --git a/cypress/helpers/util.ts b/cypress/helpers/util.ts index 74b17cf055b..52da4a72ee7 100644 --- a/cypress/helpers/util.ts +++ b/cypress/helpers/util.ts @@ -29,6 +29,7 @@ export const mermaidUrl = ( options: CypressMermaidConfig, api: boolean ): string => { + options.handDrawnSeed = 1; const codeObject: CodeObject = { code: graphStr, mermaid: options, diff --git a/cypress/integration/rendering/classDiagram-v2.spec.js b/cypress/integration/rendering/classDiagram-v2.spec.js index 258f8529f67..0c5dbc04b06 100644 --- a/cypress/integration/rendering/classDiagram-v2.spec.js +++ b/cypress/integration/rendering/classDiagram-v2.spec.js @@ -581,4 +581,63 @@ class C13["With Città foreign language"] { logLevel: 1, flowchart: { htmlLabels: false } } ); }); + + it('renders a class diagram with a generic class in a namespace', () => { + const diagramDefinition = ` + classDiagram-v2 + namespace Company.Project.Module { + class GenericClass~T~ { + +addItem(item: T) + +getItem() T + } + } + `; + + imgSnapshotTest(diagramDefinition); + }); + + it('renders a class diagram with nested namespaces and relationships', () => { + const diagramDefinition = ` + classDiagram-v2 + namespace Company.Project.Module.SubModule { + class Report { + +generatePDF(data: List) + +generateCSV(data: List) + } + } + namespace Company.Project.Module { + class Admin { + +generateReport() + } + } + Admin --> Report : generates + `; + + imgSnapshotTest(diagramDefinition); + }); + + it('renders a class diagram with multiple classes and relationships in a namespace', () => { + const diagramDefinition = ` + classDiagram-v2 + namespace Company.Project.Module { + class User { + +login(username: String, password: String) + +logout() + } + class Admin { + +addUser(user: User) + +removeUser(user: User) + +generateReport() + } + class Report { + +generatePDF(reportData: List) + +generateCSV(reportData: List) + } + } + Admin --> User : manages + Admin --> Report : generates + `; + + imgSnapshotTest(diagramDefinition); + }); }); diff --git a/cypress/integration/rendering/flowchart-handDrawn.spec.js b/cypress/integration/rendering/flowchart-handDrawn.spec.js index 10d6dde8774..49c55c628eb 100644 --- a/cypress/integration/rendering/flowchart-handDrawn.spec.js +++ b/cypress/integration/rendering/flowchart-handDrawn.spec.js @@ -12,7 +12,6 @@ describe('Flowchart HandDrawn', () => { `, { look: 'handDrawn', - handDrawnSeed: 1, flowchart: { htmlLabels: false }, fontFamily: 'courier', } @@ -30,7 +29,6 @@ describe('Flowchart HandDrawn', () => { `, { look: 'handDrawn', - handDrawnSeed: 1, flowchart: { htmlLabels: true }, fontFamily: 'courier', } @@ -47,7 +45,7 @@ describe('Flowchart HandDrawn', () => { C -->|Two| E[iPhone] C -->|Three| F[Car] `, - { look: 'handDrawn', handDrawnSeed: 1, fontFamily: 'courier' } + { look: 'handDrawn', fontFamily: 'courier' } ); }); @@ -62,7 +60,7 @@ describe('Flowchart HandDrawn', () => { C -->|Two| E[\\iPhone\\] C -->|Three| F[Car] `, - { look: 'handDrawn', handDrawnSeed: 1, fontFamily: 'courier' } + { look: 'handDrawn', fontFamily: 'courier' } ); }); @@ -78,7 +76,7 @@ describe('Flowchart HandDrawn', () => { classDef processHead fill:#888888,color:white,font-weight:bold,stroke-width:3px,stroke:#001f3f class 1A,1B,D,E processHead `, - { look: 'handDrawn', handDrawnSeed: 1, fontFamily: 'courier' } + { look: 'handDrawn', fontFamily: 'courier' } ); }); @@ -107,7 +105,7 @@ describe('Flowchart HandDrawn', () => { 35(SAM.CommonFA.PopulationFME)-->39(SAM.CommonFA.ChargeDetails) 36(SAM.CommonFA.PremetricCost)-->39(SAM.CommonFA.ChargeDetails) `, - { look: 'handDrawn', handDrawnSeed: 1, fontFamily: 'courier' } + { look: 'handDrawn', fontFamily: 'courier' } ); }); @@ -178,7 +176,7 @@ describe('Flowchart HandDrawn', () => { 9a072290_1ec3_e711_8c5a_005056ad0002-->d6072290_1ec3_e711_8c5a_005056ad0002 9a072290_1ec3_e711_8c5a_005056ad0002-->71082290_1ec3_e711_8c5a_005056ad0002 `, - { look: 'handDrawn', handDrawnSeed: 1, fontFamily: 'courier' } + { look: 'handDrawn', fontFamily: 'courier' } ); }); @@ -187,7 +185,7 @@ describe('Flowchart HandDrawn', () => { ` graph TB;subgraph "number as labels";1;end; `, - { look: 'handDrawn', handDrawnSeed: 1, fontFamily: 'courier' } + { look: 'handDrawn', fontFamily: 'courier' } ); }); @@ -199,7 +197,7 @@ describe('Flowchart HandDrawn', () => { a1-->a2 end `, - { look: 'handDrawn', handDrawnSeed: 1, fontFamily: 'courier' } + { look: 'handDrawn', fontFamily: 'courier' } ); }); @@ -211,7 +209,7 @@ describe('Flowchart HandDrawn', () => { a1-->a2 end `, - { look: 'handDrawn', handDrawnSeed: 1, fontFamily: 'courier' } + { look: 'handDrawn', fontFamily: 'courier' } ); }); @@ -246,7 +244,7 @@ describe('Flowchart HandDrawn', () => { style foo fill:#F99,stroke-width:2px,stroke:#F0F,color:darkred style bar fill:#999,stroke-width:10px,stroke:#0F0,color:blue `, - { look: 'handDrawn', handDrawnSeed: 1, fontFamily: 'courier' } + { look: 'handDrawn', fontFamily: 'courier' } ); }); @@ -348,7 +346,7 @@ describe('Flowchart HandDrawn', () => { sid-7CE72B24-E0C1-46D3-8132-8BA66BE05AA7-->sid-4DA958A0-26D9-4D47-93A7-70F39FD7D51A; sid-7CE72B24-E0C1-46D3-8132-8BA66BE05AA7-->sid-4FC27B48-A6F9-460A-A675-021F5854FE22; `, - { look: 'handDrawn', handDrawnSeed: 1, fontFamily: 'courier' } + { look: 'handDrawn', fontFamily: 'courier' } ); }); @@ -364,7 +362,6 @@ describe('Flowchart HandDrawn', () => { `, { look: 'handDrawn', - handDrawnSeed: 1, listUrl: false, listId: 'color styling', fontFamily: 'courier', @@ -390,7 +387,6 @@ describe('Flowchart HandDrawn', () => { `, { look: 'handDrawn', - handDrawnSeed: 1, listUrl: false, listId: 'color styling', fontFamily: 'courier', @@ -411,7 +407,6 @@ describe('Flowchart HandDrawn', () => { `, { look: 'handDrawn', - handDrawnSeed: 1, flowchart: { htmlLabels: false }, fontFamily: 'courier', } @@ -435,7 +430,6 @@ describe('Flowchart HandDrawn', () => { `, { look: 'handDrawn', - handDrawnSeed: 1, flowchart: { htmlLabels: false }, fontFamily: 'courier', } @@ -457,7 +451,6 @@ describe('Flowchart HandDrawn', () => { `, { look: 'handDrawn', - handDrawnSeed: 1, flowchart: { htmlLabels: false }, fontFamily: 'courier', } @@ -471,7 +464,6 @@ describe('Flowchart HandDrawn', () => { `, { look: 'handDrawn', - handDrawnSeed: 1, flowchart: { htmlLabels: false }, fontFamily: 'courier', } @@ -485,7 +477,6 @@ describe('Flowchart HandDrawn', () => { `, { look: 'handDrawn', - handDrawnSeed: 1, flowchart: { htmlLabels: false }, fontFamily: 'courier', } @@ -500,7 +491,6 @@ describe('Flowchart HandDrawn', () => { `, { look: 'handDrawn', - handDrawnSeed: 1, flowchart: { htmlLabels: false }, fontFamily: 'courier', } @@ -527,7 +517,6 @@ describe('Flowchart HandDrawn', () => { class A someclass;`, { look: 'handDrawn', - handDrawnSeed: 1, flowchart: { htmlLabels: false }, fontFamily: 'courier', } @@ -544,7 +533,7 @@ describe('Flowchart HandDrawn', () => { C -->|Two| E[iPhone] C -->|Three| F[fa:fa-car Car] `, - { look: 'handDrawn', handDrawnSeed: 1, flowchart: { nodeSpacing: 50 }, fontFamily: 'courier' } + { look: 'handDrawn', flowchart: { nodeSpacing: 50 }, fontFamily: 'courier' } ); }); @@ -560,7 +549,6 @@ describe('Flowchart HandDrawn', () => { `, { look: 'handDrawn', - handDrawnSeed: 1, flowchart: { rankSpacing: '100' }, fontFamily: 'courier', } @@ -578,7 +566,6 @@ describe('Flowchart HandDrawn', () => { `, { look: 'handDrawn', - handDrawnSeed: 1, flowchart: { htmlLabels: false }, fontFamily: 'courier', } @@ -603,7 +590,7 @@ describe('Flowchart HandDrawn', () => { click E "notes://do-your-thing/id" "other protocol test" click F "javascript:alert('test')" "script test" `, - { look: 'handDrawn', handDrawnSeed: 1, securityLevel: 'loose', fontFamily: 'courier' } + { look: 'handDrawn', securityLevel: 'loose', fontFamily: 'courier' } ); }); @@ -623,7 +610,7 @@ describe('Flowchart HandDrawn', () => { click B "index.html#link-clicked" "link test" click D testClick "click test" `, - { look: 'handDrawn', handDrawnSeed: 1, flowchart: { htmlLabels: true } } + { look: 'handDrawn', flowchart: { htmlLabels: true } } ); }); @@ -645,7 +632,6 @@ describe('Flowchart HandDrawn', () => { `, { look: 'handDrawn', - handDrawnSeed: 1, flowchart: { htmlLabels: false }, fontFamily: 'courier', } @@ -664,7 +650,7 @@ describe('Flowchart HandDrawn', () => { class A myClass1 class D myClass2 `, - { look: 'handDrawn', handDrawnSeed: 1, flowchart: { htmlLabels: true } } + { look: 'handDrawn', flowchart: { htmlLabels: true } } ); }); @@ -682,7 +668,6 @@ describe('Flowchart HandDrawn', () => { `, { look: 'handDrawn', - handDrawnSeed: 1, flowchart: { htmlLabels: false }, fontFamily: 'courier', } @@ -711,7 +696,6 @@ describe('Flowchart HandDrawn', () => { `, { look: 'handDrawn', - handDrawnSeed: 1, flowchart: { htmlLabels: false }, fontFamily: 'courier', } @@ -728,7 +712,6 @@ describe('Flowchart HandDrawn', () => { `, { look: 'handDrawn', - handDrawnSeed: 1, flowchart: { htmlLabels: false }, fontFamily: 'courier', } @@ -752,7 +735,6 @@ describe('Flowchart HandDrawn', () => { `, { look: 'handDrawn', - handDrawnSeed: 1, flowchart: { htmlLabels: false }, fontFamily: 'courier', } @@ -769,7 +751,7 @@ describe('Flowchart HandDrawn', () => { C -->|Two| E[iPhone] C -->|Three| F[fa:fa-car Car] `, - { look: 'handDrawn', handDrawnSeed: 1, flowchart: { diagramPadding: 0 } } + { look: 'handDrawn', flowchart: { diagramPadding: 0 } } ); }); @@ -804,7 +786,7 @@ describe('Flowchart HandDrawn', () => { `graph TD a["Haiya"]-->b `, - { look: 'handDrawn', handDrawnSeed: 1, htmlLabels: false, flowchart: { htmlLabels: false } } + { look: 'handDrawn', htmlLabels: false, flowchart: { htmlLabels: false } } ); }); it('FDH37: should render non-escaped with html labels', () => { @@ -814,7 +796,6 @@ describe('Flowchart HandDrawn', () => { `, { look: 'handDrawn', - handDrawnSeed: 1, htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose', @@ -830,7 +811,7 @@ describe('Flowchart HandDrawn', () => { C -->|Two| E[iPhone] C -->|Three| F[fa:fa-car Car] `, - { look: 'handDrawn', handDrawnSeed: 1, flowchart: { useMaxWidth: true } } + { look: 'handDrawn', flowchart: { useMaxWidth: true } } ); cy.get('svg').should((svg) => { expect(svg).to.have.attr('width', '100%'); @@ -853,7 +834,7 @@ describe('Flowchart HandDrawn', () => { C -->|Two| E[iPhone] C -->|Three| F[fa:fa-car Car] `, - { look: 'handDrawn', handDrawnSeed: 1, flowchart: { useMaxWidth: false } } + { look: 'handDrawn', flowchart: { useMaxWidth: false } } ); cy.get('svg').should((svg) => { // const height = parseFloat(svg.attr('height')); @@ -874,7 +855,6 @@ describe('Flowchart HandDrawn', () => { `, { look: 'handDrawn', - handDrawnSeed: 1, htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose', @@ -904,7 +884,6 @@ describe('Flowchart HandDrawn', () => { `, { look: 'handDrawn', - handDrawnSeed: 1, htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose', @@ -919,7 +898,6 @@ graph TD `, { look: 'handDrawn', - handDrawnSeed: 1, htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose', @@ -937,7 +915,6 @@ graph TD `, { look: 'handDrawn', - handDrawnSeed: 1, htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose', @@ -977,7 +954,6 @@ graph TD `, { look: 'handDrawn', - handDrawnSeed: 1, htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose', @@ -999,7 +975,6 @@ graph TD `, { look: 'handDrawn', - handDrawnSeed: 1, htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose', @@ -1016,7 +991,6 @@ graph TD `, { look: 'handDrawn', - handDrawnSeed: 1, htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose', @@ -1032,7 +1006,6 @@ graph TD `, { look: 'handDrawn', - handDrawnSeed: 1, htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose', @@ -1051,7 +1024,6 @@ graph TD `, { look: 'handDrawn', - handDrawnSeed: 1, flowchart: { htmlLabels: true }, securityLevel: 'loose', } diff --git a/cypress/integration/rendering/flowchart-shape-alias.spec.ts b/cypress/integration/rendering/flowchart-shape-alias.spec.ts new file mode 100644 index 00000000000..86aef718c28 --- /dev/null +++ b/cypress/integration/rendering/flowchart-shape-alias.spec.ts @@ -0,0 +1,142 @@ +import { imgSnapshotTest } from '../../helpers/util.ts'; + +const aliasSet1 = ['process', 'rect', 'proc', 'rectangle'] as const; + +const aliasSet2 = ['event', 'rounded'] as const; + +const aliasSet3 = ['stadium', 'pill', 'terminal'] as const; + +const aliasSet4 = ['fr-rect', 'subproc', 'subprocess', 'framed-rectangle', 'subroutine'] as const; + +const aliasSet5 = ['db', 'database', 'cylinder', 'cyl'] as const; + +const aliasSet6 = ['diam', 'decision', 'diamond'] as const; + +const aliasSet7 = ['hex', 'hexagon', 'prepare'] as const; + +const aliasSet8 = ['lean-r', 'lean-right', 'in-out'] as const; + +const aliasSet9 = ['lean-l', 'lean-left', 'out-in'] as const; + +const aliasSet10 = ['trap-b', 'trapezoid-bottom', 'priority'] as const; + +const aliasSet11 = ['trap-t', 'trapezoid-top', 'manual'] as const; + +const aliasSet12 = ['dbl-circ', 'double-circle'] as const; + +const aliasSet13 = ['notched-rectangle', 'card', 'notch-rect'] as const; + +const aliasSet14 = [ + 'lin-rect', + 'lined-rectangle', + 'lin-proc', + 'lined-process', + 'shaded-process', +] as const; + +const aliasSet15 = ['sm-circ', 'small-circle', 'start'] as const; + +const aliasSet16 = ['fr-circ', 'framed-circle', 'stop'] as const; + +const aliasSet17 = ['fork', 'join'] as const; +// brace-r', 'braces' +const aliasSet18 = ['comment', 'brace-l'] as const; + +const aliasSet19 = ['bolt', 'com-link', 'lightning-bolt'] as const; + +const aliasSet20 = ['doc', 'document'] as const; + +const aliasSet21 = ['delay', 'half-rounded-rectangle'] as const; + +const aliasSet22 = ['h-cyl', 'das', 'horizontal-cylinder'] as const; + +const aliasSet23 = ['lin-cyl', 'disk', 'lined-cylinder'] as const; + +const aliasSet24 = ['curv-trap', 'display', 'curved-trapezoid'] as const; + +const aliasSet25 = ['div-rect', 'div-proc', 'divided-rectangle', 'divided-process'] as const; + +const aliasSet26 = ['extract', 'tri', 'triangle'] as const; + +const aliasSet27 = ['win-pane', 'internal-storage', 'window-pane'] as const; + +const aliasSet28 = ['f-circ', 'junction', 'filled-circle'] as const; + +const aliasSet29 = ['lin-doc', 'lined-document'] as const; + +const aliasSet30 = ['notch-pent', 'loop-limit', 'notched-pentagon'] as const; + +const aliasSet31 = ['flip-tri', 'manual-file', 'flipped-triangle'] as const; + +const aliasSet32 = ['sl-rect', 'manual-input', 'sloped-rectangle'] as const; + +const aliasSet33 = ['docs', 'documents', 'st-doc', 'stacked-document'] as const; + +const aliasSet34 = ['procs', 'processes', 'st-rect', 'stacked-rectangle'] as const; + +const aliasSet35 = ['flag', 'paper-tape'] as const; + +const aliasSet36 = ['bow-rect', 'stored-data', 'bow-tie-rectangle'] as const; + +const aliasSet37 = ['cross-circ', 'summary', 'crossed-circle'] as const; + +const aliasSet38 = ['tag-doc', 'tagged-document'] as const; + +const aliasSet39 = ['tag-rect', 'tag-proc', 'tagged-rectangle', 'tagged-process'] as const; + +const aliasSet40 = ['collate', 'hourglass'] as const; + +// Aggregate all alias sets into a single array +const aliasSets = [ + aliasSet1, + aliasSet2, + aliasSet3, + aliasSet4, + aliasSet5, + aliasSet6, + aliasSet7, + aliasSet8, + aliasSet9, + aliasSet10, + aliasSet11, + aliasSet12, + aliasSet13, + aliasSet14, + aliasSet15, + aliasSet16, + aliasSet17, + aliasSet18, + aliasSet19, + aliasSet20, + aliasSet21, + aliasSet22, + aliasSet23, + aliasSet24, + aliasSet25, + aliasSet26, + aliasSet27, + aliasSet28, + aliasSet29, + aliasSet30, + aliasSet31, + aliasSet32, + aliasSet33, + aliasSet34, + aliasSet35, + aliasSet36, + aliasSet37, + aliasSet38, + aliasSet39, +] as const; + +aliasSets.forEach((aliasSet) => { + describe(`Test ${aliasSet.join(',')} `, () => { + it(`All ${aliasSet.join(',')} should render same shape`, () => { + let flowchartCode = `flowchart \n`; + aliasSet.forEach((alias, index) => { + flowchartCode += ` n${index}@{ shape: ${alias}, label: "${alias}" }\n`; + }); + imgSnapshotTest(flowchartCode); + }); + }); +}); diff --git a/cypress/integration/rendering/iconShape.spec.ts b/cypress/integration/rendering/iconShape.spec.ts new file mode 100644 index 00000000000..389e2d94dd1 --- /dev/null +++ b/cypress/integration/rendering/iconShape.spec.ts @@ -0,0 +1,126 @@ +import { imgSnapshotTest } from '../../helpers/util'; + +const looks = ['classic', 'handDrawn'] as const; +const directions = [ + 'TB', + //'BT', + 'LR', + // 'RL' +] as const; +const forms = [undefined, 'square', 'circle', 'rounded'] as const; +const labelPos = [undefined, 't', 'b'] as const; + +looks.forEach((look) => { + directions.forEach((direction) => { + forms.forEach((form) => { + labelPos.forEach((pos) => { + describe(`Test iconShape in ${form ? `${form} form,` : ''} ${look} look and dir ${direction} with label position ${pos ? pos : 'not defined'}`, () => { + it(`without label`, () => { + let flowchartCode = `flowchart ${direction}\n`; + flowchartCode += ` nA --> nAA@{ icon: 'fa:bell'`; + if (form) { + flowchartCode += `, form: '${form}'`; + } + flowchartCode += ` }\n`; + imgSnapshotTest(flowchartCode, { look }); + }); + + it(`with label`, () => { + let flowchartCode = `flowchart ${direction}\n`; + flowchartCode += ` nA --> nAA@{ icon: 'fa:bell', label: 'This is a label for icon shape'`; + if (form) { + flowchartCode += `, form: '${form}'`; + } + if (pos) { + flowchartCode += `, pos: '${pos}'`; + } + flowchartCode += ` }\n`; + imgSnapshotTest(flowchartCode, { look }); + }); + + it(`with very long label`, () => { + let flowchartCode = `flowchart ${direction}\n`; + flowchartCode += ` nA --> nAA@{ icon: 'fa:bell', label: 'This is a very very very very very long long long label for icon shape'`; + if (form) { + flowchartCode += `, form: '${form}'`; + } + if (pos) { + flowchartCode += `, pos: '${pos}'`; + } + flowchartCode += ` }\n`; + imgSnapshotTest(flowchartCode, { look }); + }); + + it(`with markdown htmlLabels:true`, () => { + let flowchartCode = `flowchart ${direction}\n`; + flowchartCode += ` nA --> nAA@{ icon: 'fa:bell', label: 'This is **bold** and strong for icon shape'`; + if (form) { + flowchartCode += `, form: '${form}'`; + } + if (pos) { + flowchartCode += `, pos: '${pos}'`; + } + flowchartCode += ` }\n`; + imgSnapshotTest(flowchartCode, { look }); + }); + + it(`with markdown htmlLabels:false`, () => { + let flowchartCode = `flowchart ${direction}\n`; + flowchartCode += ` nA --> nAA@{ icon: 'fa:bell', label: 'This is **bold** and strong for icon shape'`; + if (form) { + flowchartCode += `, form: '${form}'`; + } + if (pos) { + flowchartCode += `, pos: '${pos}'`; + } + flowchartCode += ` }\n`; + imgSnapshotTest(flowchartCode, { + look, + htmlLabels: false, + flowchart: { htmlLabels: false }, + }); + }); + + it(`with styles`, () => { + let flowchartCode = `flowchart ${direction}\n`; + flowchartCode += ` nA --> nAA@{ icon: 'fa:bell', label: 'new icon shape'`; + if (form) { + flowchartCode += `, form: '${form}'`; + } + if (pos) { + flowchartCode += `, pos: '${pos}'`; + } + flowchartCode += ` }\n`; + flowchartCode += ` style nAA fill:#f9f,stroke:#333,stroke-width:4px \n`; + imgSnapshotTest(flowchartCode, { look }); + }); + + it(`with classDef`, () => { + let flowchartCode = `flowchart ${direction}\n`; + flowchartCode += ` classDef customClazz fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5\n`; + flowchartCode += ` nA --> nAA@{ icon: 'fa:bell', label: 'new icon shape'`; + if (form) { + flowchartCode += `, form: '${form}'`; + } + if (pos) { + flowchartCode += `, pos: '${pos}'`; + } + flowchartCode += ` }\n`; + flowchartCode += ` nAA:::customClazz\n`; + imgSnapshotTest(flowchartCode, { look }); + }); + }); + }); + }); + }); +}); + +describe('Test iconShape with different h', () => { + it('with different h', () => { + let flowchartCode = `flowchart TB\n`; + const icon = 'fa:bell'; + const iconHeight = 64; + flowchartCode += ` nA --> nAA@{ icon: '${icon}', label: 'icon with different h', h: ${iconHeight} }\n`; + imgSnapshotTest(flowchartCode); + }); +}); diff --git a/cypress/integration/rendering/imageShape.spec.ts b/cypress/integration/rendering/imageShape.spec.ts new file mode 100644 index 00000000000..d2e267149d4 --- /dev/null +++ b/cypress/integration/rendering/imageShape.spec.ts @@ -0,0 +1,103 @@ +import { imgSnapshotTest } from '../../helpers/util'; + +const looks = ['classic', 'handDrawn'] as const; +const directions = [ + 'TB', + //'BT', + 'LR', + // 'RL' +] as const; +const labelPos = [undefined, 't', 'b'] as const; + +looks.forEach((look) => { + directions.forEach((direction) => { + labelPos.forEach((pos) => { + describe(`Test imageShape in ${look} look and dir ${direction} with label position ${pos ? pos : 'not defined'}`, () => { + it(`without label`, () => { + let flowchartCode = `flowchart ${direction}\n`; + flowchartCode += ` nA --> A@{ img: 'https://cdn.pixabay.com/photo/2020/02/22/18/49/paper-4871356_1280.jpg', w: '100', h: '100' }\n`; + imgSnapshotTest(flowchartCode, { look }); + }); + + it(`with label`, () => { + let flowchartCode = `flowchart ${direction}\n`; + flowchartCode += ` nA --> A@{ img: 'https://cdn.pixabay.com/photo/2020/02/22/18/49/paper-4871356_1280.jpg', label: 'This is a label for image shape'`; + + flowchartCode += `, w: '100', h: '200'`; + if (pos) { + flowchartCode += `, pos: '${pos}'`; + } + flowchartCode += ` }\n`; + imgSnapshotTest(flowchartCode, { look }); + }); + + it(`with very long label`, () => { + let flowchartCode = `flowchart ${direction}\n`; + flowchartCode += ` nA --> A@{ img: 'https://cdn.pixabay.com/photo/2020/02/22/18/49/paper-4871356_1280.jpg', label: 'This is a very very very very very long long long label for image shape'`; + + flowchartCode += `, w: '100', h: '250'`; + if (pos) { + flowchartCode += `, pos: '${pos}'`; + } + flowchartCode += ` }\n`; + imgSnapshotTest(flowchartCode, { look }); + }); + + it(`with markdown htmlLabels:true`, () => { + let flowchartCode = `flowchart ${direction}\n`; + flowchartCode += ` nA --> A@{ img: 'https://cdn.pixabay.com/photo/2020/02/22/18/49/paper-4871356_1280.jpg', label: 'This is **bold** and strong for image shape'`; + + flowchartCode += `, w: '550', h: '200'`; + if (pos) { + flowchartCode += `, pos: '${pos}'`; + } + flowchartCode += ` }\n`; + imgSnapshotTest(flowchartCode, { look, htmlLabels: true }); + }); + + it(`with markdown htmlLabels:false`, () => { + let flowchartCode = `flowchart ${direction}\n`; + flowchartCode += ` nA --> A@{ img: 'https://cdn.pixabay.com/photo/2020/02/22/18/49/paper-4871356_1280.jpg', label: 'This is **bold** and strong for image shape'`; + flowchartCode += `, w: '250', h: '200'`; + + if (pos) { + flowchartCode += `, pos: '${pos}'`; + } + flowchartCode += ` }\n`; + imgSnapshotTest(flowchartCode, { + look, + htmlLabels: false, + flowchart: { htmlLabels: false }, + }); + }); + + it(`with styles`, () => { + let flowchartCode = `flowchart ${direction}\n`; + flowchartCode += ` nA --> A@{ img: 'https://cdn.pixabay.com/photo/2020/02/22/18/49/paper-4871356_1280.jpg', label: 'new image shape'`; + flowchartCode += `, w: '550', h: '200'`; + + if (pos) { + flowchartCode += `, pos: '${pos}'`; + } + flowchartCode += ` }\n`; + flowchartCode += ` style A fill:#f9f,stroke:#333,stroke-width:4px \n`; + imgSnapshotTest(flowchartCode, { look }); + }); + + it(`with classDef`, () => { + let flowchartCode = `flowchart ${direction}\n`; + flowchartCode += ` classDef customClazz fill:#bbf,stroke:#f66,stroke-width:2px,color:#000000,stroke-dasharray: 5 5\n`; + flowchartCode += ` nA --> A@{ img: 'https://cdn.pixabay.com/photo/2020/02/22/18/49/paper-4871356_1280.jpg', label: 'new image shape'`; + + flowchartCode += `, w: '500', h: '550'`; + if (pos) { + flowchartCode += `, pos: '${pos}'`; + } + flowchartCode += ` }\n`; + flowchartCode += ` A:::customClazz\n`; + imgSnapshotTest(flowchartCode, { look }); + }); + }); + }); + }); +}); diff --git a/cypress/integration/rendering/newShapes.spec.ts b/cypress/integration/rendering/newShapes.spec.ts new file mode 100644 index 00000000000..6c71a38464c --- /dev/null +++ b/cypress/integration/rendering/newShapes.spec.ts @@ -0,0 +1,146 @@ +import { imgSnapshotTest } from '../../helpers/util.ts'; + +const looks = ['classic', 'handDrawn'] as const; +const directions = [ + 'TB', + //'BT', + 'LR', + //'RL' +] as const; +const newShapesSet1 = [ + 'triangle', + 'sloped-rectangle', + 'horizontal-cylinder', + 'flipped-triangle', + 'hourglass', +] as const; +const newShapesSet2 = [ + 'tagged-rectangle', + 'documents', + 'lightning-bolt', + 'filled-circle', + 'window-pane', +] as const; + +const newShapesSet3 = [ + 'curved-trapezoid', + 'bow-rect', + 'tagged-document', + 'divided-rectangle', + 'crossed-circle', +] as const; + +const newShapesSet4 = [ + 'document', + 'notched-pentagon', + 'lined-cylinder', + 'stacked-document', + 'half-rounded-rectangle', +] as const; + +const newShapesSet5 = [ + 'lined-document', + 'tagged-document', + 'brace-l', + 'comment', + 'braces', + 'brace-r', +] as const; + +const newShapesSet6 = ['brace-r', 'braces'] as const; +// Aggregate all shape sets into a single array +const newShapesSets = [ + newShapesSet1, + newShapesSet2, + newShapesSet3, + newShapesSet4, + newShapesSet5, + newShapesSet6, +]; + +looks.forEach((look) => { + directions.forEach((direction) => { + newShapesSets.forEach((newShapesSet) => { + describe(`Test ${newShapesSet.join(', ')} in ${look} look and dir ${direction}`, () => { + it(`without label`, () => { + let flowchartCode = `flowchart ${direction}\n`; + newShapesSet.forEach((newShape, index) => { + flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape} }\n`; + }); + imgSnapshotTest(flowchartCode, { look }); + }); + + it(`with label`, () => { + let flowchartCode = `flowchart ${direction}\n`; + newShapesSet.forEach((newShape, index) => { + flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape}, label: 'This is a label for ${newShape} shape' }\n`; + }); + imgSnapshotTest(flowchartCode, { look }); + }); + + it(`connect all shapes with each other`, () => { + let flowchartCode = `flowchart ${direction}\n`; + newShapesSet.forEach((newShape, index) => { + flowchartCode += ` n${index}${index}@{ shape: ${newShape}, label: 'This is a label for ${newShape} shape' }\n`; + }); + for (let i = 0; i < newShapesSet.length; i++) { + for (let j = i + 1; j < newShapesSet.length; j++) { + flowchartCode += ` n${i}${i} --> n${j}${j}\n`; + } + } + if (!(direction === 'TB' && look === 'handDrawn' && newShapesSet === newShapesSet1)) { + //skip this test, works in real. Need to look + imgSnapshotTest(flowchartCode, { look }); + } + }); + + it(`with very long label`, () => { + let flowchartCode = `flowchart ${direction}\n`; + newShapesSet.forEach((newShape, index) => { + flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape}, label: 'This is a very very very very very long long long label for ${newShape} shape' }\n`; + }); + imgSnapshotTest(flowchartCode, { look }); + }); + + it(`with markdown htmlLabels:true`, () => { + let flowchartCode = `flowchart ${direction}\n`; + newShapesSet.forEach((newShape, index) => { + flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape}, label: 'This is **bold** and strong for ${newShape} shape' }\n`; + }); + imgSnapshotTest(flowchartCode, { look }); + }); + + it(`with markdown htmlLabels:false`, () => { + let flowchartCode = `flowchart ${direction}\n`; + newShapesSet.forEach((newShape, index) => { + flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape}, label: 'This is **bold** and strong for ${newShape} shape' }\n`; + }); + imgSnapshotTest(flowchartCode, { + look, + htmlLabels: false, + flowchart: { htmlLabels: false }, + }); + }); + + it(`with styles`, () => { + let flowchartCode = `flowchart ${direction}\n`; + newShapesSet.forEach((newShape, index) => { + flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape}, label: 'new ${newShape} shape' }\n`; + flowchartCode += ` style n${index}${index} fill:#f9f,stroke:#333,stroke-width:4px \n`; + }); + imgSnapshotTest(flowchartCode, { look }); + }); + + it(`with classDef`, () => { + let flowchartCode = `flowchart ${direction}\n`; + flowchartCode += ` classDef customClazz fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5\n`; + newShapesSet.forEach((newShape, index) => { + flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape}, label: 'new ${newShape} shape' }\n`; + flowchartCode += ` n${index}${index}:::customClazz\n`; + }); + imgSnapshotTest(flowchartCode, { look }); + }); + }); + }); + }); +}); diff --git a/cypress/integration/rendering/oldShapes.spec.ts b/cypress/integration/rendering/oldShapes.spec.ts new file mode 100644 index 00000000000..628e70ea88c --- /dev/null +++ b/cypress/integration/rendering/oldShapes.spec.ts @@ -0,0 +1,107 @@ +import { imgSnapshotTest } from '../../helpers/util'; + +const looks = ['classic', 'handDrawn'] as const; +const directions = [ + 'TB', + //'BT', + 'LR', + //'RL' +] as const; + +const shapesSet1 = ['text', 'card', 'lin-rect', 'diamond', 'hexagon'] as const; + +// removing labelRect, need have alias for it +const shapesSet2 = ['rounded', 'rect', 'start', 'stop'] as const; + +const shapesSet3 = ['fork', 'choice', 'note', 'stadium', 'odd'] as const; + +const shapesSet4 = ['subroutine', 'cylinder', 'circle', 'doublecircle', 'odd'] as const; + +const shapesSet5 = ['anchor', 'lean-r', 'lean-l', 'trap-t', 'trap-b'] as const; + +// Aggregate all shape sets into a single array +const shapesSets = [shapesSet1, shapesSet2, shapesSet3, shapesSet4, shapesSet5] as const; + +looks.forEach((look) => { + directions.forEach((direction) => { + shapesSets.forEach((shapesSet) => { + describe(`Test ${shapesSet.join(', ')} in ${look} look and dir ${direction}`, () => { + it(`without label`, () => { + let flowchartCode = `flowchart ${direction}\n`; + shapesSet.forEach((newShape, index) => { + flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape} }\n`; + }); + imgSnapshotTest(flowchartCode, { look }); + }); + + it(`with label`, () => { + let flowchartCode = `flowchart ${direction}\n`; + shapesSet.forEach((newShape, index) => { + flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape}, label: 'This is a label for ${newShape} shape' }\n`; + }); + imgSnapshotTest(flowchartCode, { look }); + }); + + it(`connect all shapes with each other`, () => { + let flowchartCode = `flowchart ${direction}\n`; + shapesSet.forEach((newShape, index) => { + flowchartCode += ` n${index}${index}@{ shape: ${newShape}, label: 'This is a label for ${newShape} shape' }\n`; + }); + for (let i = 0; i < shapesSet.length; i++) { + for (let j = i + 1; j < shapesSet.length; j++) { + flowchartCode += ` n${i}${i} --> n${j}${j}\n`; + } + } + imgSnapshotTest(flowchartCode, { look }); + }); + + it(`with very long label`, () => { + let flowchartCode = `flowchart ${direction}\n`; + shapesSet.forEach((newShape, index) => { + flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape}, label: 'This is a very very very very very long long long label for ${newShape} shape' }\n`; + }); + imgSnapshotTest(flowchartCode, { look }); + }); + + it(`with markdown htmlLabels:true`, () => { + let flowchartCode = `flowchart ${direction}\n`; + shapesSet.forEach((newShape, index) => { + flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape}, label: 'This is **bold** and strong for ${newShape} shape' }\n`; + }); + imgSnapshotTest(flowchartCode, { look }); + }); + + it(`with markdown htmlLabels:false`, () => { + let flowchartCode = `flowchart ${direction}\n`; + shapesSet.forEach((newShape, index) => { + flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape}, label: 'This is **bold** and strong for ${newShape} shape' }\n`; + }); + imgSnapshotTest(flowchartCode, { + look, + htmlLabels: false, + flowchart: { htmlLabels: false }, + }); + }); + + it(`with styles`, () => { + let flowchartCode = `flowchart ${direction}\n`; + shapesSet.forEach((newShape, index) => { + flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape}, label: 'new ${newShape} shape' }\n`; + flowchartCode += ` style n${index}${index} fill:#f9f,stroke:#333,stroke-width:4px \n`; + }); + imgSnapshotTest(flowchartCode, { look }); + }); + + it(`with classDef`, () => { + let flowchartCode = `flowchart ${direction}\n`; + flowchartCode += ` classDef customClazz fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5\n`; + shapesSet.forEach((newShape, index) => { + flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape}, label: 'new ${newShape} shape' }\n`; + flowchartCode += ` n${index}${index}:::customClazz\n`; + }); + imgSnapshotTest(flowchartCode, { look }); + }); + }); + }); + }); +}); diff --git a/cypress/platform/knsv2.html b/cypress/platform/knsv2.html index 80406b93910..d93881018eb 100644 --- a/cypress/platform/knsv2.html +++ b/cypress/platform/knsv2.html @@ -83,7 +83,8 @@
-+++--- title: hello2 config: @@ -242,8 +243,190 @@ ++ ++--- +config: + look: neo +--- +flowchart RL + subgraph " " + A5@{ shape: manual-file, label: "a label"} + B5@{ shape: manual-input, label: "a label" } + C5@{ shape: mul-doc, label: "a label" } + D5@{ shape: mul-proc, label: "a label" } + E5@{ shape: paper-tape, label: "a label" } + B3@{ shape: das, label: "a label" } + C3@{ shape: disk, label: "a label" } + D4@{ shape: lin-doc, label: "a label" } + E4@{ shape: loop-limit, label: "a label" } + end + subgraph " " + B6@{ shape: summary, label: "a label" } + C6@{ shape: tag-we-rect, label: "a label" } + D6@{ shape: tag-rect, label: "a label" } + A2@{ shape: fork} + B2@{ shape: hourglass } + C2@{ shape: comment, label: "I am a comment" } + D2@{ shape: bolt } + D3@{ shape: disp, label: "a label" } + C4@{ shape: junction, label: "a label" } + A4@{ shape: extract, label: "a label"} + B52[a fr]@{ shape: fr } + end + subgraph " " + A1@{ shape: text, label: This is a textblock} + B1@{ shape: card, label: "a label" } + C1@{ shape: lined-proc, label: "a label" } + D1@{ shape: start, label: "a label" } + E1@{ shape: stop, label: "a label" } + E2@{ shape: doc, label: "a label" } + A6@{ shape: stored-data, label: "a label"} + A3@{ shape: delay, label: "a label" } + E3@{ shape: div-proc, label: "a label" } + B4[a label]@{ shape: win-pane } + end++--- + title: hello2 + config: + look: handDrawn + elk: + +--- +%%{init: {"flowchart": {"defaultRenderer": "elk"}} }%% +flowchart TD + + A([Start]) -->|go to booking page| B("select + ISBS booking no") + A --> QQ{cancel booking} + A --> RR{no show} + A --> SS{change booking} + B -->C(wmpay_request_payment.request_type= 'partial', + wmpay_request_payment.status= 'paid', + pos_booking.booking_status= ‘partial’ and 'full_deposit') + style C text-align:left + C -->D{manage booking} + + D -->|cancel|E[ระบบแสดงช่องให้กรอกเหตุผล] + E -->F{กดปุ่ม 'cancel' หรือไม่} + F -->|Yes|G[ระบบบันทึกค่าใหม่ + และไม่สามารถแก้ไขข้อมูลได้] + F -->|No|H[กดปุ่ม 'close'] + H -->|ระบบไม่เปลี่ยนแปลงข้อมูล|Z + G -->|ระบบส่งข้อมูล|I[(POS_database)] + I -->|pos_booking.booking_status='cancel'|Z([End]) + + + D -->|no show|J[ระบบแสดงช่องให้กรอกเหตุผล] + J -->K{กดปุ่ม 'noshow' หรือไม่} + K -->|Yes|L[ระบบสร้างใบเสร็จอัตโนมัติ + Product_id: 439, + ItemName: no show] + style L text-align:left + + K -->|No|O[กดปุ่ม 'close'] + O -->|ระบบไม่เปลี่ยนแปลงข้อมูล|Z + L -->M[ระบบบันทึกค่าใหม่] + M -->|ระบบส่งข้อมูล|N[(POS_database)] + N -->|pos_booking.booking_status=‘noshow’|Z + + + +++--- + title: hello2 + config: + look: handDrawn + layout: dagre + elk: + nodePlacementStrategy: BRANDES_KOEPF +--- +flowchart + A --> A + subgraph A + B --> B + subgraph B + C + end + end + + +++--- +config: + look: handdrawn + flowchart: + htmlLabels: true +--- +flowchart + A[I am a long text, where do I go??? handdrawn - true] +++++--- +config: + flowchart: + htmlLabels: false +--- +flowchart + A[I am a long text, where do I go??? classic - false] +++--- +config: + flowchart: + htmlLabels: true +--- +flowchart + A[I am a long text, where do I go??? classic - true] +++flowchart LR + id1(Start)-->id2(Stop) + style id1 fill:#f9f,stroke:#333,stroke-width:4px + style id2 fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5 + + ++ ++ flowchart LR + A:::foo & B:::bar --> C:::foobar + classDef foo stroke:#f00 + classDef bar stroke:#0f0 + classDef ash color:red + class C ash + style C stroke:#00f, fill:black + ++ ++ stateDiagram + A:::foo + B:::bar --> C:::foobar + classDef foo stroke:#f00 + classDef bar stroke:#0f0 + style C stroke:#00f, fill:black, color:white + +++flowchart TB + A@{ + label: "aksljhf kasjdh" + } ++ +