fix: rendering test cases

on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
This commit is contained in:
omkarht
2025-08-08 19:31:56 +05:30
parent 4bece53a3c
commit 716548548a
2 changed files with 300 additions and 285 deletions

View File

@@ -2,49 +2,50 @@ import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts';
const looks = ['classic'];
const participantTypes = [
'participant',
'actor',
'boundary',
'control',
'entity',
'database',
'collections',
'queue',
{ type: 'participant', display: 'participant' },
{ type: 'actor', display: 'actor' },
{ type: 'boundary', display: 'boundary' },
{ type: 'control', display: 'control' },
{ type: 'entity', display: 'entity' },
{ type: 'database', display: 'database' },
{ type: 'collections', display: 'collections' },
{ type: 'queue', display: 'queue' },
];
const interactionTypes = [
'->>', // Solid arrow with arrowhead
'-->>', // Dotted arrow with arrowhead
'->', // Solid arrow without arrowhead
'-->', // Dotted arrow without arrowhead
'-x', // Solid arrow with cross
'--x', // Dotted arrow with cross
'->>+', // Solid arrow with arrowhead (activate)
'-->>+', // Dotted arrow with arrowhead (activate)
];
const restrictedTypes = ['boundary', 'control', 'entity', 'database', 'collections', 'queue'];
const interactionTypes = ['->>', '-->>', '->', '-->', '-x', '--x', '->>+', '-->>+'];
const notePositions = ['left of', 'right of', 'over'];
function getParticipantLine(name, type, alias) {
if (restrictedTypes.includes(type)) {
return ` participant ${name}@{ "type" : "${type}" }\n`;
} else if (alias) {
return ` participant ${name}@{ "type" : "${type}" } \n`;
} else {
return ` participant ${name}@{ "type" : "${type}" }\n`;
}
}
looks.forEach((look) => {
describe(`Sequence Diagram Tests - ${look} look`, () => {
it('should render all participant types', () => {
let diagramCode = `sequenceDiagram\n`;
participantTypes.forEach((type, index) => {
diagramCode += ` ${type} ${type}${index} as ${type} ${index}\n`;
participantTypes.forEach((pt, index) => {
const name = `${pt.display}${index}`;
diagramCode += getParticipantLine(name, pt.type);
});
// Add some basic interactions
for (let i = 0; i < participantTypes.length - 1; i++) {
diagramCode += ` ${participantTypes[i]}${i} ->> ${participantTypes[i + 1]}${i + 1}: Message ${i}\n`;
diagramCode += ` ${participantTypes[i].display}${i} ->> ${participantTypes[i + 1].display}${i + 1}: Message ${i}\n`;
}
imgSnapshotTest(diagramCode, { look, sequence: { diagramMarginX: 50, diagramMarginY: 10 } });
});
it('should render all interaction types', () => {
let diagramCode = `sequenceDiagram\n`;
// Create two participants
// Add all interaction types
diagramCode += ` participant A\n`;
diagramCode += ` participant B\n`;
diagramCode += getParticipantLine('A', 'actor');
diagramCode += getParticipantLine('B', 'boundary');
interactionTypes.forEach((interaction, index) => {
diagramCode += ` A ${interaction} B: ${interaction} message ${index}\n`;
});
@@ -53,13 +54,14 @@ looks.forEach((look) => {
it('should render participant creation and destruction', () => {
let diagramCode = `sequenceDiagram\n`;
participantTypes.forEach((type, index) => {
diagramCode += ` ${type} A\n`;
diagramCode += ` ${type} B\n`;
diagramCode += ` create ${type} ${type}${index}\n`;
diagramCode += ` A ->> ${type}${index}: Hello ${type}\n`;
participantTypes.forEach((pt, index) => {
const name = `${pt.display}${index}`;
diagramCode += getParticipantLine('A', pt.type);
diagramCode += getParticipantLine('B', pt.type);
diagramCode += ` create participant ${name}@{ "type" : "${pt.type}" }\n`;
diagramCode += ` A ->> ${name}: Hello ${pt.display}\n`;
if (index % 2 === 0) {
diagramCode += ` destroy ${type}${index}\n`;
diagramCode += ` destroy ${name}\n`;
}
});
imgSnapshotTest(diagramCode, { look });
@@ -67,8 +69,8 @@ looks.forEach((look) => {
it('should render notes in all positions', () => {
let diagramCode = `sequenceDiagram\n`;
diagramCode += ` participant A\n`;
diagramCode += ` participant B\n`;
diagramCode += getParticipantLine('A', 'actor');
diagramCode += getParticipantLine('B', 'boundary');
notePositions.forEach((position, index) => {
diagramCode += ` Note ${position} A: Note ${position} ${index}\n`;
});
@@ -78,12 +80,12 @@ looks.forEach((look) => {
it('should render parallel interactions', () => {
let diagramCode = `sequenceDiagram\n`;
participantTypes.slice(0, 4).forEach((type, index) => {
diagramCode += ` ${type} ${type}${index}\n`;
participantTypes.slice(0, 4).forEach((pt, index) => {
diagramCode += getParticipantLine(`${pt.display}${index}`, pt.type);
});
diagramCode += ` par Parallel actions\n`;
for (let i = 0; i < participantTypes.length - 1; i += 2) {
diagramCode += ` ${participantTypes[i]}${i} ->> ${participantTypes[i + 1]}${i + 1}: Message ${i}\n`;
for (let i = 0; i < 3; i += 2) {
diagramCode += ` ${participantTypes[i].display}${i} ->> ${participantTypes[i + 1].display}${i + 1}: Message ${i}\n`;
if (i < participantTypes.length - 2) {
diagramCode += ` and\n`;
}
@@ -94,8 +96,8 @@ looks.forEach((look) => {
it('should render alternative flows', () => {
let diagramCode = `sequenceDiagram\n`;
diagramCode += ` participant A\n`;
diagramCode += ` participant B\n`;
diagramCode += getParticipantLine('A', 'actor');
diagramCode += getParticipantLine('B', 'boundary');
diagramCode += ` alt Successful case\n`;
diagramCode += ` A ->> B: Request\n`;
diagramCode += ` B -->> A: Success\n`;
@@ -108,12 +110,12 @@ looks.forEach((look) => {
it('should render loops', () => {
let diagramCode = `sequenceDiagram\n`;
participantTypes.slice(0, 3).forEach((type, index) => {
diagramCode += ` ${type} ${type}${index}\n`;
participantTypes.slice(0, 3).forEach((pt, index) => {
diagramCode += getParticipantLine(`${pt.display}${index}`, pt.type);
});
diagramCode += ` loop For each participant\n`;
for (let i = 0; i < 3; i++) {
diagramCode += ` ${participantTypes[0]}0 ->> ${participantTypes[1]}1: Message ${i}\n`;
diagramCode += ` ${participantTypes[0].display}0 ->> ${participantTypes[1].display}1: Message ${i}\n`;
}
diagramCode += ` end\n`;
imgSnapshotTest(diagramCode, { look });
@@ -122,27 +124,26 @@ looks.forEach((look) => {
it('should render boxes around groups', () => {
let diagramCode = `sequenceDiagram\n`;
diagramCode += ` box Group 1\n`;
participantTypes.slice(0, 3).forEach((type, index) => {
diagramCode += ` ${type} ${type}${index}\n`;
participantTypes.slice(0, 3).forEach((pt, index) => {
diagramCode += ` ${getParticipantLine(`${pt.display}${index}`, pt.type)}`;
});
diagramCode += ` end\n`;
diagramCode += ` box rgb(200,220,255) Group 2\n`;
participantTypes.slice(3, 6).forEach((type, index) => {
diagramCode += ` ${type} ${type}${index}\n`;
participantTypes.slice(3, 6).forEach((pt, index) => {
diagramCode += ` ${getParticipantLine(`${pt.display}${index}`, pt.type)}`;
});
diagramCode += ` end\n`;
// Add some interactions
diagramCode += ` ${participantTypes[0]}0 ->> ${participantTypes[3]}0: Cross-group message\n`;
diagramCode += ` ${participantTypes[0].display}0 ->> ${participantTypes[3].display}0: Cross-group message\n`;
imgSnapshotTest(diagramCode, { look });
});
it('should render with different font settings', () => {
let diagramCode = `sequenceDiagram\n`;
participantTypes.slice(0, 3).forEach((type, index) => {
diagramCode += ` ${type} ${type}${index}\n`;
participantTypes.slice(0, 3).forEach((pt, index) => {
diagramCode += getParticipantLine(`${pt.display}${index}`, pt.type);
});
diagramCode += ` ${participantTypes[0]}0 ->> ${participantTypes[1]}1: Regular message\n`;
diagramCode += ` Note right of ${participantTypes[1]}1: Regular note\n`;
diagramCode += ` ${participantTypes[0].display}0 ->> ${participantTypes[1].display}1: Regular message\n`;
diagramCode += ` Note right of ${participantTypes[1].display}1: Regular note\n`;
imgSnapshotTest(diagramCode, {
look,
sequence: {
@@ -166,15 +167,15 @@ describe('Sequence Diagram Special Cases', () => {
sequenceDiagram
box rgb(200,220,255) Authentication
actor User
boundary LoginUI
control AuthService
database UserDB
participant LoginUI@{ "type": "boundary" }
participant AuthService@{ "type": "control" }
participant UserDB@{ "type": "database" }
end
box rgb(200,255,220) Order Processing
entity Order
queue OrderQueue
collections AuditLogs
participant Order@{ "type": "entity" }
participant OrderQueue@{ "type": "queue" }
participant AuditLogs@{ "type": "collections" }
end
User ->> LoginUI: Enter credentials
@@ -231,14 +232,14 @@ describe('Sequence Diagram Special Cases', () => {
imgSnapshotTest(
`
sequenceDiagram
actor User
participant AuthService as Authentication Service
boundary UI
control OrderController
entity Product
database MongoDB
collections Products
queue OrderQueue
participant User@{ "type": "actor" }
participant AuthService@{ "type": "control" }
participant UI@{ "type": "boundary" }
participant OrderController@{ "type": "control" }
participant Product@{ "type": "entity" }
participant MongoDB@{ "type": "database" }
participant Products@{ "type": "collections" }
participant OrderQueue@{ "type": "queue" }
User ->> UI: Login request
UI ->> AuthService: Validate credentials
AuthService -->> UI: Authentication token
@@ -254,46 +255,63 @@ describe('Sequence Diagram Special Cases', () => {
});
it('should render participant creation and destruction with different types', () => {
imgSnapshotTest(
`
imgSnapshotTest(`
sequenceDiagram
actor Customer
participant Frontend
boundary PaymentGateway
Customer ->> Frontend: Place order
Frontend ->> OrderProcessor: Process order
create database OrderDB
OrderProcessor ->> OrderDB: Save order
`
);
participant Alice@{ "type" : "boundary" }
Alice->>Bob: Hello Bob, how are you ?
Bob->>Alice: Fine, thank you. And you?
create participant Carl@{ "type" : "control" }
Alice->>Carl: Hi Carl!
create actor D as Donald
Carl->>D: Hi!
destroy Carl
Alice-xCarl: We are too many
destroy Bob
Bob->>Alice: I agree
`);
});
it('should handle complex interactions between different participant types', () => {
imgSnapshotTest(
`
sequenceDiagram
box rgba(200,220,255,0.5) System Components
actor User
boundary WebUI
control API
entity BusinessLogic
database MainDB
end
box rgba(200,255,220,0.5) External Services
queue MessageQueue
database AuditLogs
box rgb(200,220,255) Authentication
participant User@{ "type": "actor" }
participant LoginUI@{ "type": "boundary" }
participant AuthService@{ "type": "control" }
participant UserDB@{ "type": "database" }
end
User ->> WebUI: Submit request
WebUI ->> API: Process request
API ->> BusinessLogic: Execute business rules
BusinessLogic ->> MainDB: Query data
MainDB -->> BusinessLogic: Return results
BusinessLogic ->> MessageQueue: Publish event
MessageQueue -->> AuditLogs: Store audit trail
AuditLogs -->> API: Audit complete
API -->> WebUI: Return response
WebUI -->> User: Show results
box rgb(200,255,220) Order Processing
participant Order@{ "type": "entity" }
participant OrderQueue@{ "type": "queue" }
participant AuditLogs@{ "type": "collections" }
end
User ->> LoginUI: Enter credentials
LoginUI ->> AuthService: Validate
AuthService ->> UserDB: Query user
UserDB -->> AuthService: User data
alt Valid credentials
AuthService -->> LoginUI: Success
LoginUI -->> User: Welcome
par Place order
User ->> Order: New order
Order ->> OrderQueue: Process
and
Order ->> AuditLogs: Record
end
loop Until confirmed
OrderQueue ->> Order: Update status
Order -->> User: Notification
end
else Invalid credentials
AuthService --x LoginUI: Failure
LoginUI --x User: Retry
end
`,
{ sequence: { useMaxWidth: false } }
);
@@ -303,13 +321,13 @@ describe('Sequence Diagram Special Cases', () => {
imgSnapshotTest(
`
sequenceDiagram
actor Customer
participant Frontend
boundary PaymentService
control InventoryManager
entity Order
database OrdersDB
queue NotificationQueue
participant Customer@{ "type": "actor" }
participant Frontend@{ "type": "participant" }
participant PaymentService@{ "type": "boundary" }
participant InventoryManager@{ "type": "control" }
participant Order@{ "type": "entity" }
participant OrdersDB@{ "type": "database" }
participant NotificationQueue@{ "type": "queue" }
Customer ->> Frontend: Place order
Frontend ->> Order: Create order
@@ -327,18 +345,18 @@ describe('Sequence Diagram Special Cases', () => {
`
);
});
});
it('should render different participant types with notes and loops', () => {
imgSnapshotTest(
`
sequenceDiagram
actor Admin
participant Dashboard
boundary AuthService
control UserManager
entity UserProfile
database UserDB
database Logs
participant AuthService@{ "type" : "boundary" }
participant UserManager@{ "type" : "control" }
participant UserProfile@{ "type" : "entity" }
participant UserDB@{ "type" : "database" }
participant Logs@{ "type" : "database" }
Admin ->> Dashboard: Open user management
loop Authentication check
@@ -364,11 +382,11 @@ describe('Sequence Diagram Special Cases', () => {
sequenceDiagram
actor Client
participant MobileApp
boundary CloudService
control DataProcessor
entity Transaction
database TransactionsDB
queue EventBus
participant CloudService@{ "type" : "boundary" }
participant DataProcessor@{ "type" : "control" }
participant Transaction@{ "type" : "entity" }
participant TransactionsDB@{ "type" : "database" }
participant EventBus@{ "type" : "queue" }
Client ->> MobileApp: Initiate transaction
MobileApp ->> CloudService: Authenticate
@@ -392,16 +410,13 @@ describe('Sequence Diagram Special Cases', () => {
imgSnapshotTest(
`
sequenceDiagram
actor LongNameUser as User With A Very<br/>Long Name
participant FE as Frontend Service<br/>With Long Name
boundary B as Boundary With<br/>Multiline Name
control C as Control With<br/>Multiline Name
entity E as Entity With<br/>Multiline Name
database DB as Database With<br/>Multiline Name
collections COL as Collections With<br/>Multiline Name
queue Q as Queue With<br/>Multiline Name
participant B@{ "type" : "boundary" }
participant C@{ "type" : "control" }
participant E@{ "type" : "entity" }
participant DB@{ "type" : "database" }
participant COL@{ "type" : "collections" }
participant Q@{ "type" : "queue" }
LongNameUser ->> FE: This is a very long message that should wrap properly in the diagram
FE ->> B: Another long message<br/>with explicit<br/>line breaks
B -->> FE: Response message that is also quite long and needs to wrap
FE ->> C: Process data
@@ -416,12 +431,13 @@ describe('Sequence Diagram Special Cases', () => {
{ sequence: { wrap: true } }
);
});
describe('Sequence Diagram - New Participant Types with Long Notes and Messages', () => {
it('should render long notes left of boundary', () => {
imgSnapshotTest(
`
sequenceDiagram
boundary Alice
participant Alice@{ "type" : "boundary" }
actor Bob
Alice->>Bob: Hola
Note left of Alice: Extremely utterly long line of longness which had previously overflown the actor box as it is much longer than what it should be
@@ -435,7 +451,7 @@ describe('Sequence Diagram Special Cases', () => {
imgSnapshotTest(
`
sequenceDiagram
control Alice
participant Alice@{ "type" : "control" }
actor Bob
Alice->>Bob: Hola
Note left of Alice:wrap: Extremely utterly long line of longness which had previously overflown the actor box as it is much longer than what it should be
@@ -449,7 +465,7 @@ describe('Sequence Diagram Special Cases', () => {
imgSnapshotTest(
`
sequenceDiagram
entity Alice
participant Alice@{ "type" : "entity" }
actor Bob
Alice->>Bob: Hola
Note right of Alice: Extremely utterly long line of longness which had previously overflown the actor box as it is much longer than what it should be
@@ -463,7 +479,7 @@ describe('Sequence Diagram Special Cases', () => {
imgSnapshotTest(
`
sequenceDiagram
database Alice
participant Alice@{ "type" : "database" }
actor Bob
Alice->>Bob: Hola
Note right of Alice:wrap: Extremely utterly long line of longness which had previously overflown the actor box as it is much longer than what it should be
@@ -477,7 +493,7 @@ describe('Sequence Diagram Special Cases', () => {
imgSnapshotTest(
`
sequenceDiagram
collections Alice
participant Alice@{ "type" : "collections" }
actor Bob
Alice->>Bob: Hola
Note over Alice: Extremely utterly long line of longness which had previously overflown the actor box as it is much longer than what it should be
@@ -491,7 +507,7 @@ describe('Sequence Diagram Special Cases', () => {
imgSnapshotTest(
`
sequenceDiagram
queue Alice
participant Alice@{ "type" : "queue" }
actor Bob
Alice->>Bob: Hola
Note over Alice:wrap: Extremely utterly long line of longness which had previously overflown the actor box as it is much longer than what it should be
@@ -506,7 +522,7 @@ describe('Sequence Diagram Special Cases', () => {
`
sequenceDiagram
actor Alice
boundary Charlie
participant Charlie@{ "type" : "boundary" }
note over Alice: Some note
note over Charlie: Other note
`,
@@ -518,8 +534,8 @@ describe('Sequence Diagram Special Cases', () => {
imgSnapshotTest(
`
sequenceDiagram
database Alice
collections Bob
participant Alice@{ "type" : "database" }
participant Bob@{ "type" : "collections" }
Alice->>Bob: Extremely utterly long line of longness which had previously overflown the actor box as it is much longer than what it should be
Bob->>Alice: I'm short though
`,
@@ -531,8 +547,8 @@ describe('Sequence Diagram Special Cases', () => {
imgSnapshotTest(
`
sequenceDiagram
control Alice
entity Bob
participant Alice@{ "type" : "control" }
participant Bob@{ "type" : "entity" }
Alice->>Bob:wrap: Extremely utterly long line of longness which had previously overflown the actor box as it is much longer than what it should be
Bob->>Alice: I'm short though
`,
@@ -544,8 +560,8 @@ describe('Sequence Diagram Special Cases', () => {
imgSnapshotTest(
`
sequenceDiagram
queue Alice
boundary Bob
participant Alice@{ "type" : "queue" }
participant Bob@{ "type" : "boundary" }
Alice->>Bob: I'm short
Bob->>Alice: Extremely utterly long line of longness which had previously overflown the actor box as it is much longer than what it should be
`,
@@ -558,7 +574,7 @@ describe('Sequence Diagram Special Cases', () => {
`
sequenceDiagram
actor Alice
database Bob
participant Bob@{ "type" : "database" }
Alice->>Bob: I'm short
Bob->>Alice:wrap: Extremely utterly long line of longness which had previously overflown the actor box as it is much longer than what it should be
`,
@@ -566,7 +582,6 @@ describe('Sequence Diagram Special Cases', () => {
);
});
});
});
describe('svg size', () => {
it('should render a sequence diagram when useMaxWidth is true (default)', () => {
@@ -574,8 +589,8 @@ describe('Sequence Diagram Special Cases', () => {
`
sequenceDiagram
actor Alice
boundary Bob
control John as John<br/>Second Line
participant Bob@{ "type" : "boundary" }
participant John@{ "type" : "control" }
Alice ->> Bob: Hello Bob, how are you?
Bob-->>John: How about you John?
Bob--x Alice: I am good thanks!
@@ -611,8 +626,8 @@ describe('Sequence Diagram Special Cases', () => {
`
sequenceDiagram
actor Alice
boundary Bob
control John as John<br/>Second Line
participant Bob@{ "type" : "boundary" }
participant John@{ "type" : "control" }
Alice ->> Bob: Hello Bob, how are you?
Bob-->>John: How about you John?
Bob--x Alice: I am good thanks!

View File

@@ -553,7 +553,7 @@ export class SequenceDB implements DiagramDB {
);
}
this.state.records.lastCreated = param.actor;
this.addActor(param.actor, param.actor, param.description, param.draw);
this.addActor(param.actor, param.actor, param.description, param.draw, param.config);
this.state.records.createdActors.set(param.actor, this.state.records.messages.length);
break;
case 'destroyParticipant':