mirror of
				https://github.com/mermaid-js/mermaid.git
				synced 2025-10-31 02:44:17 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			498 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			498 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| import { imgSnapshotTest, renderGraph } from '../../helpers/util';
 | |
| 
 | |
| describe('State diagram', () => {
 | |
|   it('v2 should render a simple info', () => {
 | |
|     imgSnapshotTest(
 | |
|       `
 | |
|     info
 | |
|       `,
 | |
|       { logLevel: 1, fontFamily: 'courier' }
 | |
|     );
 | |
|     cy.get('svg');
 | |
|   });
 | |
|   it('v2 should render a simple state diagrams', () => {
 | |
|     imgSnapshotTest(
 | |
|       `
 | |
|     stateDiagram-v2
 | |
| 
 | |
|     [*] --> State1
 | |
|     State1 --> [*]
 | |
|       `,
 | |
|       { logLevel: 0, fontFamily: 'courier' }
 | |
|     );
 | |
|     cy.get('svg');
 | |
|   });
 | |
|   it('v2 should render a long descriptions instead of id when available', () => {
 | |
|     imgSnapshotTest(
 | |
|       `
 | |
|       stateDiagram-v2
 | |
| 
 | |
|       [*] --> S1
 | |
|       state "Some long name" as S1
 | |
|       `,
 | |
|       { logLevel: 0, fontFamily: 'courier' }
 | |
|     );
 | |
|     cy.get('svg');
 | |
|   });
 | |
|   it('v2 should render a long descriptions with additional descriptions', () => {
 | |
|     imgSnapshotTest(
 | |
|       `
 | |
|       stateDiagram-v2
 | |
| 
 | |
|       [*] --> S1
 | |
|       state "Some long name" as S1: The description
 | |
|       `,
 | |
|       { logLevel: 0, fontFamily: 'courier' }
 | |
|     );
 | |
|     cy.get('svg');
 | |
|   });
 | |
|   it('v2 should render a single state with short descriptions', () => {
 | |
|     imgSnapshotTest(
 | |
|       `
 | |
|     stateDiagram-v2
 | |
|       state "A long long name" as long1
 | |
|       state "A" as longlonglongid
 | |
|       `,
 | |
|       { logLevel: 0, fontFamily: 'courier' }
 | |
|     );
 | |
|     cy.get('svg');
 | |
|   });
 | |
|   it('v2 should render a transition descriptions with new lines', () => {
 | |
|     imgSnapshotTest(
 | |
|       `
 | |
|       stateDiagram-v2
 | |
| 
 | |
|       [*] --> S1
 | |
|       S1 --> S2: long line using<br/>should work
 | |
|       S1 --> S3: long line using <br>should work
 | |
|       S1 --> S4: long line using \\nshould work
 | |
|       `,
 | |
|       { logLevel: 0, fontFamily: 'courier' }
 | |
|     );
 | |
|     cy.get('svg');
 | |
|   });
 | |
|   it('v2 should render a state with a note', () => {
 | |
|     imgSnapshotTest(
 | |
|       `
 | |
|     stateDiagram-v2
 | |
|     State1: The state with a note
 | |
|     note right of State1
 | |
|       Important information! You can write
 | |
|       notes.
 | |
|     end note
 | |
|       `,
 | |
|       { logLevel: 0, fontFamily: 'courier' }
 | |
|     );
 | |
|     cy.get('svg');
 | |
|   });
 | |
|   it('v2 should render a state with on the left side when so specified', () => {
 | |
|     imgSnapshotTest(
 | |
|       `
 | |
|     stateDiagram-v2
 | |
|     State1: The state with a note with minus - and plus + in it
 | |
|     note left of State1
 | |
|       Important information! You can write
 | |
|       notes with . and  in them.
 | |
|     end note
 | |
|       `,
 | |
|       { logLevel: 0, fontFamily: 'courier' }
 | |
|     );
 | |
|     cy.get('svg');
 | |
|   });
 | |
|   it('v2 should render a state with a note together with another state', () => {
 | |
|     imgSnapshotTest(
 | |
|       `
 | |
|     stateDiagram-v2
 | |
|     State1: The state with a note +,-
 | |
|     note right of State1
 | |
|       Important information! You can write +,-
 | |
|       notes.
 | |
|     end note
 | |
|     State1 --> State2 : With +,-
 | |
|     note left of State2 : This is the note +,-<br/>
 | |
|       `,
 | |
|       { logLevel: 0, fontFamily: 'courier' }
 | |
|     );
 | |
|     cy.get('svg');
 | |
|   });
 | |
|   it('v2 should render a note with multiple lines in it', () => {
 | |
|     imgSnapshotTest(
 | |
|       `
 | |
|     stateDiagram-v2
 | |
|     State1: The state with a note
 | |
|     note right of State1
 | |
|       Important information! You\ncan write
 | |
|       notes with multiple lines...
 | |
|       Here is another line...
 | |
|       And another line...
 | |
|     end note
 | |
|     `,
 | |
|       { logLevel: 0, fontFamily: 'courier' }
 | |
|     );
 | |
|   });
 | |
|   it('v2 should handle multiline notes with different line breaks', () => {
 | |
|     imgSnapshotTest(
 | |
|       `
 | |
|       stateDiagram-v2
 | |
|       State1
 | |
|       note right of State1
 | |
|       Line1<br>Line2<br/>Line3<br />Line4<br	/>Line5
 | |
|       end note
 | |
|       `,
 | |
|       { logLevel: 0, fontFamily: 'courier' }
 | |
|     );
 | |
|   });
 | |
| 
 | |
|   it('v2 should render a states with descriptions including multi-line descriptions', () => {
 | |
|     imgSnapshotTest(
 | |
|       `
 | |
|     stateDiagram-v2
 | |
|     State1: This a a single line description
 | |
|     State2: This a a multi line description
 | |
|     State2: here comes the multi part
 | |
|     [*] --> State1
 | |
|     State1 --> State2
 | |
|     State2 --> [*]
 | |
|       `,
 | |
|       { logLevel: 0, fontFamily: 'courier' }
 | |
|     );
 | |
|     cy.get('svg');
 | |
|   });
 | |
|   it('v2 should render a simple state diagrams', () => {
 | |
|     imgSnapshotTest(
 | |
|       `
 | |
|     stateDiagram-v2
 | |
|     [*] --> State1
 | |
|     State1 --> State2
 | |
|     State1 --> State3
 | |
|     State1 --> [*]
 | |
|       `,
 | |
|       { logLevel: 0, fontFamily: 'courier' }
 | |
|     );
 | |
|     cy.get('svg');
 | |
|   });
 | |
|   it('v2 should render a simple state diagrams with labels', () => {
 | |
|     imgSnapshotTest(
 | |
|       `
 | |
|     stateDiagram-v2
 | |
|     [*] --> State1
 | |
|     State1 --> State2 : Transition 1
 | |
|     State1 --> State3 : Transition 2
 | |
|     State1 --> State4 : Transition 3
 | |
|     State1 --> State5 : Transition 4
 | |
|     State2 --> State3 : Transition 5
 | |
|     State1 --> [*]
 | |
|       `,
 | |
|       { logLevel: 0, fontFamily: 'courier' }
 | |
|     );
 | |
|     cy.get('svg');
 | |
|   });
 | |
|   it('v2 should render state descriptions', () => {
 | |
|     imgSnapshotTest(
 | |
|       `
 | |
|       stateDiagram-v2
 | |
|         state "Long state description" as XState1
 | |
|         state "Another Long state description" as XState2
 | |
|         XState2 : New line
 | |
|         XState1 --> XState2
 | |
|       `,
 | |
|       { logLevel: 0, fontFamily: 'courier' }
 | |
|     );
 | |
|     cy.get('svg');
 | |
|   });
 | |
|   it('v2 should render composite states', () => {
 | |
|     imgSnapshotTest(
 | |
|       `
 | |
|       stateDiagram-v2
 | |
|       [*] --> NotShooting: Pacifist
 | |
|       NotShooting --> A
 | |
|       NotShooting --> B
 | |
|       NotShooting --> C
 | |
| 
 | |
|       state NotShooting {
 | |
|         [*] --> Idle: Yet another long long öong öong öong label
 | |
|         Idle --> Configuring : EvConfig
 | |
|         Configuring --> Idle : EvConfig  EvConfig EvConfig  EvConfig EvConfig
 | |
|       }
 | |
|       `,
 | |
|       { logLevel: 0, fontFamily: 'courier' }
 | |
|     );
 | |
|     cy.get('svg');
 | |
|   });
 | |
|   it('v2 should render multiple composite states', () => {
 | |
|     imgSnapshotTest(
 | |
|       `
 | |
|       stateDiagram-v2
 | |
|       [*]-->TV
 | |
| 
 | |
|       state TV {
 | |
|         [*] --> Off: Off to start with
 | |
|         On --> Off : Turn off
 | |
|         Off --> On : Turn on
 | |
|       }
 | |
| 
 | |
|       TV--> Console
 | |
| 
 | |
|       state Console {
 | |
|         [*] --> Off2: Off to start with
 | |
|         On2--> Off2 : Turn off
 | |
|         Off2 --> On2 : Turn on
 | |
|         On2-->Playing
 | |
| 
 | |
|         state Playing {
 | |
|           Alive --> Dead
 | |
|           Dead-->Alive
 | |
|          }
 | |
|       }
 | |
|       `,
 | |
|       { logLevel: 0, fontFamily: 'courier' }
 | |
|     );
 | |
|   });
 | |
|   it('v2 should render forks in composite states', () => {
 | |
|     imgSnapshotTest(
 | |
|       `
 | |
|       stateDiagram-v2
 | |
|       [*]-->TV
 | |
| 
 | |
|       state TV {
 | |
|         state fork_state <<fork>>
 | |
|         [*] --> fork_state
 | |
|         fork_state --> State2
 | |
|         fork_state --> State3
 | |
| 
 | |
|         state join_state <<join>>
 | |
|         State2 --> join_state
 | |
|         State3 --> join_state
 | |
|         join_state --> State4
 | |
|         State4 --> [*]
 | |
|       }
 | |
|       `,
 | |
|       { logLevel: 0, fontFamily: 'courier' }
 | |
|     );
 | |
|   });
 | |
|   it('v2 should render forks and joins', () => {
 | |
|     imgSnapshotTest(
 | |
|       `
 | |
|     stateDiagram-v2
 | |
|     state fork_state <<fork>>
 | |
|       [*] --> fork_state
 | |
|       fork_state --> State2
 | |
|       fork_state --> State3
 | |
| 
 | |
|       state join_state <<join>>
 | |
|       State2 --> join_state
 | |
|       State3 --> join_state
 | |
|       join_state --> State4
 | |
|       State4 --> [*]
 | |
|     `,
 | |
|       { logLevel: 0, fontFamily: 'courier' }
 | |
|     );
 | |
|     cy.get('svg');
 | |
|   });
 | |
|   it('v2 should render concurrency states', () => {
 | |
|     imgSnapshotTest(
 | |
|       `
 | |
|     stateDiagram-v2
 | |
|     [*] --> Active
 | |
| 
 | |
|     state Active {
 | |
|       [*] --> NumLockOff
 | |
|       NumLockOff --> NumLockOn : EvNumLockPressed
 | |
|       NumLockOn --> NumLockOff : EvNumLockPressed
 | |
|       --
 | |
|       [*] --> CapsLockOff
 | |
|       CapsLockOff --> CapsLockOn : EvCapsLockPressed
 | |
|       CapsLockOn --> CapsLockOff : EvCapsLockPressed
 | |
|       --
 | |
|       [*] --> ScrollLockOff
 | |
|       ScrollLockOff --> ScrollLockOn : EvCapsLockPressed
 | |
|       ScrollLockOn --> ScrollLockOff : EvCapsLockPressed
 | |
|     }
 | |
|     `,
 | |
|       { logLevel: 0, fontFamily: 'courier' }
 | |
|     );
 | |
|     cy.get('svg');
 | |
|   });
 | |
|   it('v2 should render a state with states in it', () => {
 | |
|     imgSnapshotTest(
 | |
|       `
 | |
|       stateDiagram-v2
 | |
|       state PilotCockpit {
 | |
|         state  Parent {
 | |
|           C
 | |
|         }
 | |
|     }
 | |
|     `,
 | |
|       {
 | |
|         logLevel: 0,
 | |
|       }
 | |
|     );
 | |
|   });
 | |
|   it('v2 it should be possibel to use a choice', () => {
 | |
|     imgSnapshotTest(
 | |
|       `
 | |
|   stateDiagram-v2
 | |
|     [*] --> Off
 | |
|     Off --> On
 | |
|     state MyChoice [[choice]]
 | |
|     On --> MyChoice
 | |
|     MyChoice --> Washing
 | |
|     MyChoice --> Drying
 | |
|     Washing --> Finished
 | |
|     Finished --> [*]
 | |
|     `,
 | |
|       {
 | |
|         logLevel: 0,
 | |
|       }
 | |
|     );
 | |
|   });
 | |
|   it('v2 width of compond state should grow with title if title is wider', () => {
 | |
|     imgSnapshotTest(
 | |
|       `
 | |
| stateDiagram-v2
 | |
|   state "Long state name 2" as NotShooting {
 | |
|     a-->b
 | |
|   }
 | |
|     `,
 | |
|       {
 | |
|         logLevel: 0,
 | |
|       }
 | |
|     );
 | |
|   });
 | |
|   it('v2 state label with names in it', () => {
 | |
|     imgSnapshotTest(
 | |
|       `
 | |
|       stateDiagram-v2
 | |
|         Yswsii: Your state with spaces in it
 | |
|         [*] --> Yswsii
 | |
|     `,
 | |
|       {
 | |
|         logLevel: 0,
 | |
|       }
 | |
|     );
 | |
|   });
 | |
|   it('v2 Simplest composite state', () => {
 | |
|     imgSnapshotTest(
 | |
|       `
 | |
|       stateDiagram-v2
 | |
|         state  Parent {
 | |
|           C
 | |
|         }
 | |
|     `,
 | |
|       {
 | |
|         logLevel: 0,
 | |
|         fontFamily: 'courier',
 | |
|       }
 | |
|     );
 | |
|   });
 | |
|   it('v2 should handle multiple arrows from one node to another', () => {
 | |
|     imgSnapshotTest(
 | |
|       `
 | |
|       stateDiagram-v2
 | |
|         a --> b: Start
 | |
|         a --> b: Stop
 | |
|     `,
 | |
|       {
 | |
|         logLevel: 0,
 | |
|         fontFamily: 'courier',
 | |
|       }
 | |
|     );
 | |
|   });
 | |
|   it('v2 should handle multiple notes added to one state', () => {
 | |
|     imgSnapshotTest(
 | |
|       `
 | |
| stateDiagram-v2
 | |
|     MyState
 | |
|     note left of MyState : I am a leftie
 | |
|     note right of MyState : I am a rightie
 | |
|     `,
 | |
|       {
 | |
|         logLevel: 0,
 | |
|         fontFamily: 'courier',
 | |
|       }
 | |
|     );
 | |
|   });
 | |
|   it('v2 should handle different rendering directions in composite states', () => {
 | |
|     imgSnapshotTest(
 | |
|       `
 | |
| stateDiagram-v2
 | |
|   direction LR
 | |
|   state A {
 | |
|     direction BT
 | |
|     a --> b
 | |
|   }
 | |
|   state C {
 | |
|     direction RL
 | |
|     c --> d
 | |
|   }
 | |
|   A --> C
 | |
|     `,
 | |
|       {
 | |
|         logLevel: 0,
 | |
|         fontFamily: 'courier',
 | |
|       }
 | |
|     );
 | |
|   });
 | |
|   it('v2 handle transition from one state in a composite state to a composite state', () => {
 | |
|     imgSnapshotTest(
 | |
|       `
 | |
| stateDiagram-v2
 | |
|   state S1 {
 | |
|     sub1 -->sub2
 | |
|   }
 | |
| 
 | |
|   state S2 {
 | |
|     sub4
 | |
|   }
 | |
|   S1 --> S2
 | |
|   sub1 --> sub4
 | |
|     `,
 | |
|       {
 | |
|         logLevel: 0,
 | |
|         fontFamily: 'courier',
 | |
|       }
 | |
|     );
 | |
|   });
 | |
|   it('v2 should render a state diagram when useMaxWidth is true (default)', () => {
 | |
|     renderGraph(
 | |
|       `
 | |
|     stateDiagram-v2
 | |
| 
 | |
|     [*] --> State1
 | |
|     State1 --> [*]
 | |
|       `,
 | |
|       { state: { useMaxWidth: true } }
 | |
|     );
 | |
|     cy.get('svg').should((svg) => {
 | |
|       expect(svg).to.have.attr('width', '100%');
 | |
|       expect(svg).to.have.attr('height');
 | |
|       const height = parseFloat(svg.attr('height'));
 | |
|       expect(height).to.be.within(177, 178);
 | |
|       const style = svg.attr('style');
 | |
|       expect(style).to.match(/^max-width: [\d.]+px;$/);
 | |
|       const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
 | |
|       // use within because the absolute value can be slightly different depending on the environment ±5%
 | |
|       expect(maxWidthValue).to.be.within(135 * 0.95, 135 * 1.05);
 | |
|     });
 | |
|   });
 | |
|   it('v2 should render a state diagram when useMaxWidth is false', () => {
 | |
|     renderGraph(
 | |
|       `
 | |
|     stateDiagram-v2
 | |
| 
 | |
|     [*] --> State1
 | |
|     State1 --> [*]
 | |
|       `,
 | |
|       { state: { useMaxWidth: false } }
 | |
|     );
 | |
|     cy.get('svg').should((svg) => {
 | |
|       const height = parseFloat(svg.attr('height'));
 | |
|       const width = parseFloat(svg.attr('width'));
 | |
|       expect(height).to.be.within(177, 178);
 | |
|       // use within because the absolute value can be slightly different depending on the environment ±5%
 | |
|       expect(width).to.be.within(135 * 0.95, 135 * 1.05);
 | |
|       expect(svg).to.not.have.attr('style');
 | |
|     });
 | |
|   });
 | |
| });
 | 
