/* eslint-env jasmine */ import { parser } from './parser/sequenceDiagram'; import sequenceDb from './sequenceDb'; import renderer from './sequenceRenderer'; function addConf(conf, key, value) { if (value !== undefined) { conf[key] = value; } return conf; } describe('when parsing a sequenceDiagram', function() { beforeEach(function() { parser.yy = sequenceDb; parser.yy.clear(); }); it('it should handle a sequenceDiagram definition', function() { const str = 'sequenceDiagram\n' + 'Alice->Bob:Hello Bob, how are you?\n' + 'Note right of Bob: Bob thinks\n' + 'Bob-->Alice: I am good thanks!'; parser.parse(str); const actors = parser.yy.getActors(); expect(actors.Alice.description).toBe('Alice'); actors.Bob.description = 'Bob'; const messages = parser.yy.getMessages(); expect(messages.length).toBe(3); expect(messages[0].from).toBe('Alice'); expect(messages[2].from).toBe('Bob'); }); it('it should handle a sequenceDiagram definition with a title', function() { const str = 'sequenceDiagram\n' + 'title: Diagram Title\n' + 'Alice->Bob:Hello Bob, how are you?\n' + 'Note right of Bob: Bob thinks\n' + 'Bob-->Alice: I am good thanks!'; parser.parse(str); const actors = parser.yy.getActors(); expect(actors.Alice.description).toBe('Alice'); actors.Bob.description = 'Bob'; const messages = parser.yy.getMessages(); const title = parser.yy.getTitle(); expect(messages.length).toBe(3); expect(messages[0].from).toBe('Alice'); expect(messages[2].from).toBe('Bob'); expect(title).toBe('Diagram Title'); }); it('it should space in actor names', function() { const str = 'sequenceDiagram\n' + 'Alice->Bob:Hello Bob, how are - you?\n' + 'Bob-->Alice: I am good thanks!'; parser.parse(str); const actors = parser.yy.getActors(); expect(actors.Alice.description).toBe('Alice'); actors.Bob.description = 'Bob'; const messages = parser.yy.getMessages(); expect(messages.length).toBe(2); expect(messages[0].from).toBe('Alice'); expect(messages[1].from).toBe('Bob'); }); it('it should alias participants', function() { const str = 'sequenceDiagram\n' + 'participant A as Alice\n' + 'participant B as Bob\n' + 'A->B:Hello Bob, how are you?\n' + 'B-->A: I am good thanks!'; parser.parse(str); const actors = parser.yy.getActors(); expect(Object.keys(actors)).toEqual(['A', 'B']); expect(actors.A.description).toBe('Alice'); expect(actors.B.description).toBe('Bob'); const messages = parser.yy.getMessages(); expect(messages.length).toBe(2); expect(messages[0].from).toBe('A'); expect(messages[1].from).toBe('B'); }); it('it should handle in async messages', function() { const str = 'sequenceDiagram\n' + 'Alice-xBob:Hello Bob, how are you?'; parser.parse(str); const actors = parser.yy.getActors(); expect(actors.Alice.description).toBe('Alice'); expect(actors.Bob.description).toBe('Bob'); const messages = parser.yy.getMessages(); expect(messages.length).toBe(1); expect(messages[0].type).toBe(parser.yy.LINETYPE.SOLID_CROSS); }); it('it should handle in async dotted messages', function() { const str = 'sequenceDiagram\n' + 'Alice--xBob:Hello Bob, how are you?'; parser.parse(str); const actors = parser.yy.getActors(); expect(actors.Alice.description).toBe('Alice'); expect(actors.Bob.description).toBe('Bob'); const messages = parser.yy.getMessages(); expect(messages.length).toBe(1); expect(messages[0].type).toBe(parser.yy.LINETYPE.DOTTED_CROSS); }); it('it should handle in arrow messages', function() { const str = 'sequenceDiagram\n' + 'Alice->>Bob:Hello Bob, how are you?'; parser.parse(str); const actors = parser.yy.getActors(); expect(actors.Alice.description).toBe('Alice'); expect(actors.Bob.description).toBe('Bob'); const messages = parser.yy.getMessages(); expect(messages.length).toBe(1); expect(messages[0].type).toBe(parser.yy.LINETYPE.SOLID); }); it('it should handle in arrow messages', function() { const str = 'sequenceDiagram\n' + 'Alice-->>Bob:Hello Bob, how are you?'; parser.parse(str); const actors = parser.yy.getActors(); expect(actors.Alice.description).toBe('Alice'); expect(actors.Bob.description).toBe('Bob'); const messages = parser.yy.getMessages(); expect(messages.length).toBe(1); expect(messages[0].type).toBe(parser.yy.LINETYPE.DOTTED); }); it('it should handle actor activation', function() { const str = 'sequenceDiagram\n' + 'Alice-->>Bob:Hello Bob, how are you?\n' + 'activate Bob\n' + "Bob-->>Alice:Hello Alice, I'm fine and you?\n" + 'deactivate Bob'; parser.parse(str); const actors = parser.yy.getActors(); expect(actors.Alice.description).toBe('Alice'); expect(actors.Bob.description).toBe('Bob'); const messages = parser.yy.getMessages(); expect(messages.length).toBe(4); expect(messages[0].type).toBe(parser.yy.LINETYPE.DOTTED); expect(messages[1].type).toBe(parser.yy.LINETYPE.ACTIVE_START); expect(messages[1].from.actor).toBe('Bob'); expect(messages[2].type).toBe(parser.yy.LINETYPE.DOTTED); expect(messages[3].type).toBe(parser.yy.LINETYPE.ACTIVE_END); expect(messages[3].from.actor).toBe('Bob'); }); it('it should handle actor one line notation activation', function() { const str = 'sequenceDiagram\n' + 'Alice-->>+Bob:Hello Bob, how are you?\n' + "Bob-->>- Alice:Hello Alice, I'm fine and you?"; parser.parse(str); const actors = parser.yy.getActors(); expect(actors.Alice.description).toBe('Alice'); expect(actors.Bob.description).toBe('Bob'); const messages = parser.yy.getMessages(); expect(messages.length).toBe(4); expect(messages[0].type).toBe(parser.yy.LINETYPE.DOTTED); expect(messages[1].type).toBe(parser.yy.LINETYPE.ACTIVE_START); expect(messages[1].from.actor).toBe('Bob'); expect(messages[2].type).toBe(parser.yy.LINETYPE.DOTTED); expect(messages[3].type).toBe(parser.yy.LINETYPE.ACTIVE_END); expect(messages[3].from.actor).toBe('Bob'); }); it('it should handle stacked activations', function() { const str = 'sequenceDiagram\n' + 'Alice-->>+Bob:Hello Bob, how are you?\n' + 'Bob-->>+Carol:Carol, let me introduce Alice?\n' + 'Bob-->>- Alice:Hello Alice, please meet Carol?\n' + "Carol->>- Bob:Oh Bob, I'm so happy to be here!"; parser.parse(str); const actors = parser.yy.getActors(); expect(actors.Alice.description).toBe('Alice'); expect(actors.Bob.description).toBe('Bob'); const messages = parser.yy.getMessages(); expect(messages.length).toBe(8); expect(messages[0].type).toBe(parser.yy.LINETYPE.DOTTED); expect(messages[1].type).toBe(parser.yy.LINETYPE.ACTIVE_START); expect(messages[1].from.actor).toBe('Bob'); expect(messages[2].type).toBe(parser.yy.LINETYPE.DOTTED); expect(messages[3].type).toBe(parser.yy.LINETYPE.ACTIVE_START); expect(messages[3].from.actor).toBe('Carol'); expect(messages[5].type).toBe(parser.yy.LINETYPE.ACTIVE_END); expect(messages[5].from.actor).toBe('Bob'); expect(messages[7].type).toBe(parser.yy.LINETYPE.ACTIVE_END); expect(messages[7].from.actor).toBe('Carol'); }); it('it should handle fail parsing when activating an inactive participant', function() { const str = `sequenceDiagram participant user as End User participant Server as Server participant System as System participant System2 as System2 user->>+Server: Test user->>+Server: Test2 user->>System: Test Server->>-user: Test Server->>-user: Test2 %% The following deactivation of Server will fail Server->>-user: Test3`; let error = false; try { parser.parse(str); } catch(e) { console.log(e.hash); error = true; } expect(error).toBe(true); }); it('it should handle comments in a sequenceDiagram', function() { const str = 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n' + '%% Comment\n' + 'Note right of Bob: Bob thinks\n' + 'Bob-->Alice: I am good thanks!'; parser.parse(str); const actors = parser.yy.getActors(); expect(actors.Alice.description).toBe('Alice'); actors.Bob.description = 'Bob'; const messages = parser.yy.getMessages(); expect(messages.length).toBe(3); expect(messages[0].from).toBe('Alice'); expect(messages[2].from).toBe('Bob'); }); it('it should handle new lines in a sequenceDiagram', function() { const str = 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n\n' + '%% Comment\n' + 'Note right of Bob: Bob thinks\n' + 'Bob-->Alice: I am good thanks!\n'; parser.parse(str); const actors = parser.yy.getActors(); expect(actors.Alice.description).toBe('Alice'); actors.Bob.description = 'Bob'; const messages = parser.yy.getMessages(); expect(messages.length).toBe(3); expect(messages[0].from).toBe('Alice'); expect(messages[2].from).toBe('Bob'); }); it('it should handle semicolons', function() { const str = 'sequenceDiagram;' + 'Alice->Bob: Hello Bob, how are you?;' + 'Note right of Bob: Bob thinks;' + 'Bob-->Alice: I am good thanks!;'; parser.parse(str); const actors = parser.yy.getActors(); expect(actors.Alice.description).toBe('Alice'); actors.Bob.description = 'Bob'; const messages = parser.yy.getMessages(); expect(messages.length).toBe(3); expect(messages[0].from).toBe('Alice'); expect(messages[2].from).toBe('Bob'); }); it('it should handle one leading space in lines in a sequenceDiagram', function() { const str = 'sequenceDiagram\n' + ' Alice->Bob: Hello Bob, how are you?\n\n' + '%% Comment\n' + 'Note right of Bob: Bob thinks\n' + 'Bob-->Alice: I am good thanks!'; parser.parse(str); const actors = parser.yy.getActors(); expect(actors.Alice.description).toBe('Alice'); actors.Bob.description = 'Bob'; const messages = parser.yy.getMessages(); expect(messages.length).toBe(3); expect(messages[0].from).toBe('Alice'); expect(messages[2].from).toBe('Bob'); }); it('it should handle several leading spaces in lines in a sequenceDiagram', function() { const str = 'sequenceDiagram\n' + ' Alice->Bob: Hello Bob, how are you?\n\n' + '%% Comment\n' + 'Note right of Bob: Bob thinks\n' + 'Bob-->Alice: I am good thanks!'; parser.parse(str); const actors = parser.yy.getActors(); expect(actors.Alice.description).toBe('Alice'); actors.Bob.description = 'Bob'; const messages = parser.yy.getMessages(); expect(messages.length).toBe(3); expect(messages[0].from).toBe('Alice'); expect(messages[2].from).toBe('Bob'); }); it('it should handle several leading spaces in lines in a sequenceDiagram', function() { const str = 'sequenceDiagram\n' + 'participant Alice\n' + 'participant Bob\n' + 'Alice->John: Hello John, how are you?\n' + ' loop Healthcheck\n' + 'John->John: Fight against hypochondria\n' + ' end\n' + 'Note right of John: Rational thoughts
prevail...\n' + ' John-->Alice: Great!\n' + ' John->Bob: How about you?\n' + 'Bob-->John: Jolly good!'; parser.parse(str); const actors = parser.yy.getActors(); expect(actors.Alice.description).toBe('Alice'); actors.Bob.description = 'Bob'; const messages = parser.yy.getMessages(); expect(messages.length).toBe(8); expect(messages[0].from).toBe('Alice'); expect(messages[2].from).toBe('John'); }); it('it should handle different line breaks', function() { const str = 'sequenceDiagram\n' + 'participant 1 as multiline
text\n' + 'participant 2 as multiline
text\n' + 'participant 3 as multiline
text\n' + 'participant 4 as multiline
text\n' + '1->>2: multiline
text\n' + 'note right of 2: multiline
text\n' + '2->>3: multiline
text\n' + 'note right of 3: multiline
text\n' + '3->>4: multiline
text\n' + 'note right of 4: multiline
text\n' + '4->>1: multiline
text\n' + 'note right of 1: multiline
text\n'; parser.parse(str); const actors = parser.yy.getActors(); expect(actors['1'].description).toBe('multiline
text'); expect(actors['2'].description).toBe('multiline
text'); expect(actors['3'].description).toBe('multiline
text'); expect(actors['4'].description).toBe('multiline
text'); const messages = parser.yy.getMessages(); expect(messages[0].message).toBe('multiline
text'); expect(messages[1].message).toBe('multiline
text'); expect(messages[2].message).toBe('multiline
text'); expect(messages[3].message).toBe('multiline
text'); expect(messages[4].message).toBe('multiline
text'); expect(messages[5].message).toBe('multiline
text'); expect(messages[6].message).toBe('multiline
text'); expect(messages[7].message).toBe('multiline
text'); }); it('it should handle notes over a single actor', function() { const str = 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n' + 'Note over Bob: Bob thinks\n'; parser.parse(str); const messages = parser.yy.getMessages(); expect(messages[1].from).toBe('Bob'); expect(messages[1].to).toBe('Bob'); }); it('it should handle notes over multiple actors', function() { const str = 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n' + 'Note over Alice,Bob: confusion\n' + 'Note over Bob,Alice: resolution\n'; parser.parse(str); const messages = parser.yy.getMessages(); expect(messages[1].from).toBe('Alice'); expect(messages[1].to).toBe('Bob'); expect(messages[2].from).toBe('Bob'); expect(messages[2].to).toBe('Alice'); }); it('it should handle loop statements', function() { const str = 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n\n' + '%% Comment\n' + 'Note right of Bob: Bob thinks\n' + 'loop Multiple happy responses\n\n' + 'Bob-->Alice: I am good thanks!\n' + 'end'; parser.parse(str); const actors = parser.yy.getActors(); expect(actors.Alice.description).toBe('Alice'); actors.Bob.description = 'Bob'; const messages = parser.yy.getMessages(); expect(messages.length).toBe(5); expect(messages[0].from).toBe('Alice'); expect(messages[1].from).toBe('Bob'); }); it('it should add a rect around sequence', function() { const str = ` sequenceDiagram Alice->Bob: Hello Bob, how are you? %% Comment rect rgb(200, 255, 200) Note right of Bob: Bob thinks Bob-->Alice: I am good thanks end `; parser.parse(str); const actors = parser.yy.getActors(); expect(actors.Alice.description).toBe('Alice'); actors.Bob.description = 'Bob'; const messages = parser.yy.getMessages(); expect(messages[1].type).toEqual(parser.yy.LINETYPE.RECT_START); expect(messages[1].message).toBe('rgb(200, 255, 200)'); expect(messages[2].type).toEqual(parser.yy.LINETYPE.NOTE); expect(messages[3].type).toEqual(parser.yy.LINETYPE.DOTTED_OPEN); expect(messages[4].type).toEqual(parser.yy.LINETYPE.RECT_END); }); it('it should allow for nested rects', function() { const str = ` sequenceDiagram Alice->Bob: Hello Bob, how are you? %% Comment rect rgb(200, 255, 200) rect rgb(0, 0, 0) Note right of Bob: Bob thinks end Bob-->Alice: I am good thanks end `; parser.parse(str); const actors = parser.yy.getActors(); expect(actors.Alice.description).toBe('Alice'); actors.Bob.description = 'Bob'; const messages = parser.yy.getMessages(); expect(messages[1].type).toEqual(parser.yy.LINETYPE.RECT_START); expect(messages[1].message).toBe('rgb(200, 255, 200)'); expect(messages[2].type).toEqual(parser.yy.LINETYPE.RECT_START); expect(messages[2].message).toBe('rgb(0, 0, 0)'); expect(messages[3].type).toEqual(parser.yy.LINETYPE.NOTE); expect(messages[4].type).toEqual(parser.yy.LINETYPE.RECT_END); expect(messages[5].type).toEqual(parser.yy.LINETYPE.DOTTED_OPEN); expect(messages[6].type).toEqual(parser.yy.LINETYPE.RECT_END); }); it('it should handle opt statements', function() { const str = 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n\n' + '%% Comment\n' + 'Note right of Bob: Bob thinks\n' + 'opt Perhaps a happy response\n\n' + 'Bob-->Alice: I am good thanks!\n' + 'end'; parser.parse(str); const actors = parser.yy.getActors(); expect(actors.Alice.description).toBe('Alice'); actors.Bob.description = 'Bob'; const messages = parser.yy.getMessages(); expect(messages.length).toBe(5); expect(messages[0].from).toBe('Alice'); expect(messages[1].from).toBe('Bob'); }); it('it should handle alt statements', function() { const str = 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n\n' + '%% Comment\n' + 'Note right of Bob: Bob thinks\n' + 'alt isWell\n\n' + 'Bob-->Alice: I am good thanks!\n' + 'else isSick\n' + 'Bob-->Alice: Feel sick...\n' + 'end'; parser.parse(str); const actors = parser.yy.getActors(); expect(actors.Alice.description).toBe('Alice'); actors.Bob.description = 'Bob'; const messages = parser.yy.getMessages(); expect(messages.length).toBe(7); expect(messages[0].from).toBe('Alice'); expect(messages[1].from).toBe('Bob'); }); it('it should handle alt statements with multiple elses', function() { const str = 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n\n' + '%% Comment\n' + 'Note right of Bob: Bob thinks\n' + 'alt isWell\n\n' + 'Bob-->Alice: I am good thanks!\n' + 'else isSick\n' + 'Bob-->Alice: Feel sick...\n' + 'else default\n' + 'Bob-->Alice: :-)\n' + 'end'; parser.parse(str); const messages = parser.yy.getMessages(); expect(messages.length).toBe(9); expect(messages[1].from).toBe('Bob'); expect(messages[2].type).toBe(parser.yy.LINETYPE.ALT_START); expect(messages[3].from).toBe('Bob'); expect(messages[4].type).toBe(parser.yy.LINETYPE.ALT_ELSE); expect(messages[5].from).toBe('Bob'); expect(messages[6].type).toBe(parser.yy.LINETYPE.ALT_ELSE); expect(messages[7].from).toBe('Bob'); expect(messages[8].type).toBe(parser.yy.LINETYPE.ALT_END); }); it('it should handle par statements a sequenceDiagram', function() { const str = 'sequenceDiagram\n' + 'par Parallel one\n' + 'Alice->>Bob: Hello Bob, how are you?\n' + 'Bob-->>Alice: I am good thanks!\n' + 'and Parallel two\n' + 'Alice->>Bob: Are you OK?\n' + 'Bob-->>Alice: Fine!\n' + 'and Parallel three\n' + 'Alice->>Bob: What do you think about it?\n' + "Bob-->>Alice: It's good!\n" + 'end'; parser.parse(str); const actors = parser.yy.getActors(); expect(actors.Alice.description).toBe('Alice'); expect(actors.Bob.description).toBe('Bob'); const messages = parser.yy.getMessages(); expect(messages.length).toBe(10); expect(messages[0].message).toBe('Parallel one'); expect(messages[1].from).toBe('Alice'); expect(messages[2].from).toBe('Bob'); }); it('it should handle special characters in signals', function() { const str = 'sequenceDiagram\n' + 'Alice->Bob: -:<>,;# comment'; parser.parse(str); const messages = parser.yy.getMessages(); expect(messages[0].message).toBe('-:<>,'); }); it('it should handle special characters in notes', function() { const str = 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n' + 'Note right of Bob: -:<>,;# comment'; parser.parse(str); const messages = parser.yy.getMessages(); expect(messages[1].message).toBe('-:<>,'); }); it('it should handle special characters in loop', function() { const str = 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n' + 'loop -:<>,;# comment\n' + 'Bob-->Alice: I am good thanks!\n' + 'end'; parser.parse(str); const messages = parser.yy.getMessages(); expect(messages[1].message).toBe('-:<>,'); }); it('it should handle special characters in opt', function() { const str = 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n' + 'opt -:<>,;# comment\n' + 'Bob-->Alice: I am good thanks!\n' + 'end'; parser.parse(str); const messages = parser.yy.getMessages(); expect(messages[1].message).toBe('-:<>,'); }); it('it should handle special characters in alt', function() { const str = 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n' + 'alt -:<>,;# comment\n' + 'Bob-->Alice: I am good thanks!\n' + 'else ,<>:-#; comment\n' + 'Bob-->Alice: I am good thanks!\n' + 'end'; parser.parse(str); const messages = parser.yy.getMessages(); expect(messages[1].message).toBe('-:<>,'); expect(messages[3].message).toBe(',<>:-'); }); it('it should handle special characters in par', function() { const str = 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n' + 'par -:<>,;# comment\n' + 'Bob-->Alice: I am good thanks!\n' + 'and ,<>:-#; comment\n' + 'Bob-->Alice: I am good thanks!\n' + 'end'; parser.parse(str); const messages = parser.yy.getMessages(); expect(messages[1].message).toBe('-:<>,'); expect(messages[3].message).toBe(',<>:-'); }); it('it should handle no-label loop', function() { const str = 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n' + 'loop\n' + 'Bob-->Alice: I am good thanks!\n' + 'end'; parser.parse(str); const messages = parser.yy.getMessages(); expect(messages[1].message).toBe(''); expect(messages[2].message).toBe('I am good thanks!'); }); it('it should handle no-label opt', function() { const str = 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n' + 'opt # comment\n' + 'Bob-->Alice: I am good thanks!\n' + 'end'; parser.parse(str); const messages = parser.yy.getMessages(); expect(messages[1].message).toBe(''); expect(messages[2].message).toBe('I am good thanks!'); }); it('it should handle no-label alt', function() { const str = 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n' + 'alt;' + 'Bob-->Alice: I am good thanks!\n' + 'else # comment\n' + 'Bob-->Alice: I am good thanks!\n' + 'end'; parser.parse(str); const messages = parser.yy.getMessages(); expect(messages[1].message).toBe(''); expect(messages[2].message).toBe('I am good thanks!'); expect(messages[3].message).toBe(''); expect(messages[4].message).toBe('I am good thanks!'); }); it('it should handle no-label par', function() { const str = 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n' + 'par;' + 'Bob-->Alice: I am good thanks!\n' + 'and # comment\n' + 'Bob-->Alice: I am good thanks!\n' + 'end'; parser.parse(str); const messages = parser.yy.getMessages(); expect(messages[1].message).toBe(''); expect(messages[2].message).toBe('I am good thanks!'); expect(messages[3].message).toBe(''); expect(messages[4].message).toBe('I am good thanks!'); }); }); describe('when checking the bounds in a sequenceDiagram', function() { let conf; beforeEach(function() { parser.yy = sequenceDb; parser.yy.clear(); conf = { diagramMarginX: 50, diagramMarginY: 10, actorMargin: 50, width: 150, // Height of actor boxes height: 65, boxMargin: 10, messageMargin: 40, boxTextMargin: 15, noteMargin: 25 }; renderer.setConf(conf); }); it('it should handle a simple bound call', function() { renderer.bounds.init(); renderer.bounds.insert(100, 100, 200, 200); const bounds = renderer.bounds.getBounds(); expect(bounds.startx).toBe(100); expect(bounds.starty).toBe(100); expect(bounds.stopx).toBe(200); expect(bounds.stopy).toBe(200); }); it('it should handle an expanding bound', function() { renderer.bounds.init(); renderer.bounds.insert(100, 100, 200, 200); renderer.bounds.insert(25, 50, 300, 400); const bounds = renderer.bounds.getBounds(); expect(bounds.startx).toBe(25); expect(bounds.starty).toBe(50); expect(bounds.stopx).toBe(300); expect(bounds.stopy).toBe(400); }); it('it should handle inserts within the bound without changing the outer bounds', function() { renderer.bounds.init(); renderer.bounds.insert(100, 100, 200, 200); renderer.bounds.insert(25, 50, 300, 400); renderer.bounds.insert(125, 150, 150, 200); const bounds = renderer.bounds.getBounds(); expect(bounds.startx).toBe(25); expect(bounds.starty).toBe(50); expect(bounds.stopx).toBe(300); expect(bounds.stopy).toBe(400); }); it('it should handle a loop without expanding the area', function() { renderer.bounds.init(); renderer.bounds.insert(25, 50, 300, 400); renderer.bounds.verticalPos = 150; renderer.bounds.newLoop(); renderer.bounds.insert(125, 150, 150, 200); const loop = renderer.bounds.endLoop(); expect(loop.startx).toBe(125 - conf.boxMargin); expect(loop.starty).toBe(150 - conf.boxMargin); expect(loop.stopx).toBe(150 + conf.boxMargin); expect(loop.stopy).toBe(200 + conf.boxMargin); // Check bounds of first loop const bounds = renderer.bounds.getBounds(); expect(bounds.startx).toBe(25); expect(bounds.starty).toBe(50); expect(bounds.stopx).toBe(300); expect(bounds.stopy).toBe(400); }); it('it should handle multiple loops withtout expanding the bounds', function() { renderer.bounds.init(); renderer.bounds.insert(100, 100, 1000, 1000); renderer.bounds.verticalPos = 200; renderer.bounds.newLoop(); renderer.bounds.newLoop(); renderer.bounds.insert(200, 200, 300, 300); // Check bounds of first loop let loop = renderer.bounds.endLoop(); expect(loop.startx).toBe(200 - conf.boxMargin); expect(loop.starty).toBe(200 - conf.boxMargin); expect(loop.stopx).toBe(300 + conf.boxMargin); expect(loop.stopy).toBe(300 + conf.boxMargin); // Check bounds of second loop loop = renderer.bounds.endLoop(); expect(loop.startx).toBe(200 - 2 * conf.boxMargin); expect(loop.starty).toBe(200 - 2 * conf.boxMargin); expect(loop.stopx).toBe(300 + 2 * conf.boxMargin); expect(loop.stopy).toBe(300 + 2 * conf.boxMargin); // Check bounds of first loop const bounds = renderer.bounds.getBounds(); expect(bounds.startx).toBe(100); expect(bounds.starty).toBe(100); expect(bounds.stopx).toBe(1000); expect(bounds.stopy).toBe(1000); }); it('it should handle a loop that expands the area', function() { renderer.bounds.init(); renderer.bounds.insert(100, 100, 200, 200); renderer.bounds.verticalPos = 200; renderer.bounds.newLoop(); renderer.bounds.insert(50, 50, 300, 300); const loop = renderer.bounds.endLoop(); expect(loop.startx).toBe(50 - conf.boxMargin); expect(loop.starty).toBe(50 - conf.boxMargin); expect(loop.stopx).toBe(300 + conf.boxMargin); expect(loop.stopy).toBe(300 + conf.boxMargin); // Check bounds after the loop const bounds = renderer.bounds.getBounds(); expect(bounds.startx).toBe(loop.startx); expect(bounds.starty).toBe(loop.starty); expect(bounds.stopx).toBe(loop.stopx); expect(bounds.stopy).toBe(loop.stopy); }); }); describe('when rendering a sequenceDiagram', function() { let conf; beforeEach(function() { parser.yy = sequenceDb; parser.yy.clear(); conf = { diagramMarginX: 50, diagramMarginY: 10, actorMargin: 50, width: 150, // Height of actor boxes height: 65, boxMargin: 10, messageMargin: 40, boxTextMargin: 15, noteMargin: 25 }; renderer.setConf(conf); }); ['tspan', 'fo', 'old', undefined].forEach(function(textPlacement) { it('it should handle one actor, when textPlacement is ' + textPlacement, function() { renderer.setConf(addConf(conf, 'textPlacement', textPlacement)); renderer.bounds.init(); const str = 'sequenceDiagram\n' + 'participant Alice'; parser.parse(str); renderer.draw(str, 'tst'); const bounds = renderer.bounds.getBounds(); expect(bounds.startx).toBe(0); expect(bounds.starty).toBe(0); expect(bounds.stopx).toBe(conf.width); expect(bounds.stopy).toBe(conf.height); }); }); it('it should handle same actor with different whitespace properly', function() { renderer.bounds.init(); const str = 'sequenceDiagram\n' + 'participant Alice\n' + 'participant Alice \n' + 'participant Alice \n'; parser.parse(str); const actors = parser.yy.getActors(); expect(Object.keys(actors)).toEqual(['Alice']); }); it('it should handle one actor and a centered note', function() { renderer.bounds.init(); const str = 'sequenceDiagram\n' + 'participant Alice\n' + 'Note over Alice: Alice thinks\n'; parser.parse(str); renderer.draw(str, 'tst'); const bounds = renderer.bounds.getBounds(); expect(bounds.startx).toBe(0); expect(bounds.starty).toBe(0); expect(bounds.stopx).toBe(conf.width); // 10 comes from mock of text height expect(bounds.stopy).toBe(conf.height + conf.boxMargin + 2 * conf.noteMargin + 10); }); it('it should handle one actor and a note to the left', function() { renderer.bounds.init(); const str = 'sequenceDiagram\n' + 'participant Alice\n' + 'Note left of Alice: Alice thinks'; parser.parse(str); renderer.draw(str, 'tst'); const bounds = renderer.bounds.getBounds(); expect(bounds.startx).toBe(-(conf.width / 2) - conf.actorMargin / 2); expect(bounds.starty).toBe(0); expect(bounds.stopx).toBe(conf.width); // 10 comes from mock of text height expect(bounds.stopy).toBe(conf.height + conf.boxMargin + 2 * conf.noteMargin + 10); }); it('it should handle one actor and a note to the right', function() { renderer.bounds.init(); const str = 'sequenceDiagram\n' + 'participant Alice\n' + 'Note right of Alice: Alice thinks'; parser.parse(str); renderer.draw(str, 'tst'); const bounds = renderer.bounds.getBounds(); expect(bounds.startx).toBe(0); expect(bounds.starty).toBe(0); expect(bounds.stopx).toBe(conf.width / 2 + conf.actorMargin / 2 + conf.width); // 10 comes from mock of text height expect(bounds.stopy).toBe(conf.height + conf.boxMargin + 2 * conf.noteMargin + 10); }); it('it should handle two actors', function() { renderer.bounds.init(); const str = 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?'; parser.parse(str); renderer.draw(str, 'tst'); const bounds = renderer.bounds.getBounds(); expect(bounds.startx).toBe(0); expect(bounds.starty).toBe(0); expect(bounds.stopx).toBe(conf.width * 2 + conf.actorMargin); expect(bounds.stopy).toBe(0 + conf.messageMargin + conf.height); }); it('it should handle two actors and two centered shared notes', function() { renderer.bounds.init(); const str = 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n' + 'Note over Alice,Bob: Looks\n' + 'Note over Bob,Alice: Looks back\n'; parser.parse(str); renderer.draw(str, 'tst'); const bounds = renderer.bounds.getBounds(); expect(bounds.startx).toBe(0); expect(bounds.starty).toBe(0); expect(bounds.stopx).toBe(conf.width * 2 + conf.actorMargin); expect(bounds.stopy).toBe( conf.height + conf.messageMargin + 2 * (conf.boxMargin + 2 * conf.noteMargin + 10) ); }); it('it should draw two actors and two messages', function() { renderer.bounds.init(); const str = 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n' + 'Bob->Alice: Fine!'; parser.parse(str); renderer.draw(str, 'tst'); const bounds = renderer.bounds.getBounds(); expect(bounds.startx).toBe(0); expect(bounds.starty).toBe(0); expect(bounds.stopx).toBe(0 + conf.width * 2 + conf.actorMargin); expect(bounds.stopy).toBe(0 + 2 * conf.messageMargin + conf.height); }); it('it should draw two actors notes to the right', function() { renderer.bounds.init(); const str = 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n' + 'Note right of Bob: Bob thinks\n' + 'Bob->Alice: Fine!'; parser.parse(str); renderer.draw(str, 'tst'); const bounds = renderer.bounds.getBounds(); expect(bounds.startx).toBe(0); expect(bounds.starty).toBe(0); const expStopX = conf.actorMargin + conf.width + conf.width / 2 + conf.noteMargin + conf.width; expect(bounds.stopx).toBe(expStopX); expect(bounds.stopy).toBe( 2 * conf.messageMargin + conf.height + conf.boxMargin + 10 + 2 * conf.noteMargin ); }); it('it should draw two actors notes to the left', function() { renderer.bounds.init(); const str = 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n' + 'Note left of Alice: Bob thinks\n' + 'Bob->Alice: Fine!'; parser.parse(str); renderer.draw(str, 'tst'); const bounds = renderer.bounds.getBounds(); expect(bounds.startx).toBe(-(conf.width / 2) - conf.actorMargin / 2); expect(bounds.starty).toBe(0); expect(bounds.stopx).toBe(conf.width * 2 + conf.actorMargin); expect(bounds.stopy).toBe( 2 * conf.messageMargin + conf.height + conf.boxMargin + 10 + 2 * conf.noteMargin ); }); it('it should draw two loops', function() { renderer.bounds.init(); const str = 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n' + 'loop Cheers\n' + 'Bob->Alice: Fine!\n' + 'end'; parser.parse(str); renderer.draw(str, 'tst'); const bounds = renderer.bounds.getBounds(); expect(bounds.startx).toBe(0); expect(bounds.starty).toBe(0); expect(bounds.stopx).toBe(0 + conf.width * 2 + conf.actorMargin); expect(bounds.stopy).toBe( 0 + 2 * conf.messageMargin + conf.height + 3 * conf.boxMargin + conf.boxTextMargin ); }); it('it should draw background rect', function() { renderer.bounds.init(); const str = ` sequenceDiagram Alice->Bob: Hello Bob, are you alright? rect rgb(0, 0, 0) Bob->Alice: I feel surrounded by darkness end `; parser.parse(str); renderer.draw(str, 'tst'); const bounds = renderer.bounds.getBounds(); expect(bounds.startx).toBe(0); expect(bounds.starty).toBe(0); expect(bounds.stopx).toBe(0 + conf.width * 2 + conf.actorMargin); expect(bounds.stopy).toBe(0 + 2 * conf.messageMargin + conf.height + 3 * conf.boxMargin); }); }); describe('when rendering a sequenceDiagram with actor mirror activated', function() { let conf; beforeEach(function() { parser.yy = sequenceDb; parser.yy.clear(); conf = { diagramMarginX: 50, diagramMarginY: 10, actorMargin: 50, width: 150, // Height of actor boxes height: 65, boxMargin: 10, messageMargin: 40, boxTextMargin: 15, noteMargin: 25, mirrorActors: true, // Depending on css styling this might need adjustment // Prolongs the edge of the diagram downwards bottomMarginAdj: 1 }; renderer.setConf(conf); }); ['tspan', 'fo', 'old', undefined].forEach(function(textPlacement) { it('it should handle one actor, when textPlacement is' + textPlacement, function() { renderer.setConf(addConf(conf, 'textPlacement', textPlacement)); renderer.bounds.init(); const str = 'sequenceDiagram\n' + 'participant Alice'; parser.parse(str); renderer.draw(str, 'tst'); const bounds = renderer.bounds.getBounds(); expect(bounds.startx).toBe(0); expect(bounds.starty).toBe(0); expect(bounds.stopx).toBe(conf.width); expect(bounds.stopy).toBe(2 * conf.height + 2 * conf.boxMargin); }); }); });