Skip to content

Commit 3f8d807

Browse files
committed
Fix: Add unit tests for Mermaid sequence diagram escaping #2
1 parent b47a6c2 commit 3f8d807

File tree

8 files changed

+151
-26
lines changed

8 files changed

+151
-26
lines changed

build.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,10 @@ fs.readFile(manifestFile, "utf-8", (err, content) => {
3737
fs.readFile(layoutFile, "utf-8", (err, content) => {
3838
if (err) throw err;
3939

40-
const regex = /\<div class="version"\>(.*?)\<\/div\>/;
40+
const regex = /\<div id="buildTimestamp" class="text-xs"\>(.*?)\<\/div\>/;
4141
const updatedContent = content.replace(
4242
regex,
43-
`<div class="version">v${version} (Build: ${timestamp} UTC)</div>`
43+
`<div id="buildTimestamp" class="text-xs">v${version} (Build: ${timestamp} UTC)</div>`
4444
);
4545

4646
fs.writeFile(layoutFile, updatedContent, "utf-8", (err) => {

coverage/coverage-summary.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
{"total": {"lines":{"total":3600,"covered":1709,"skipped":0,"pct":47.47},"statements":{"total":3600,"covered":1709,"skipped":0,"pct":47.47},"functions":{"total":52,"covered":37,"skipped":0,"pct":71.15},"branches":{"total":394,"covered":287,"skipped":0,"pct":72.84},"branchesTrue":{"total":0,"covered":0,"skipped":0,"pct":100}}
1+
{"total": {"lines":{"total":3648,"covered":1746,"skipped":0,"pct":47.86},"statements":{"total":3648,"covered":1746,"skipped":0,"pct":47.86},"functions":{"total":54,"covered":38,"skipped":0,"pct":70.37},"branches":{"total":403,"covered":294,"skipped":0,"pct":72.95},"branchesTrue":{"total":0,"covered":0,"skipped":0,"pct":100}}
22
,"C:\\Users\\yuta\\Documents\\har\\HARlytics\\vite.config.js": {"lines":{"total":37,"covered":0,"skipped":0,"pct":0},"functions":{"total":1,"covered":0,"skipped":0,"pct":0},"statements":{"total":37,"covered":0,"skipped":0,"pct":0},"branches":{"total":1,"covered":0,"skipped":0,"pct":0}}
33
,"C:\\Users\\yuta\\Documents\\har\\HARlytics\\src\\lib\\CookieTable.svelte": {"lines":{"total":68,"covered":68,"skipped":0,"pct":100},"functions":{"total":2,"covered":2,"skipped":0,"pct":100},"statements":{"total":68,"covered":68,"skipped":0,"pct":100},"branches":{"total":11,"covered":6,"skipped":0,"pct":54.54}}
44
,"C:\\Users\\yuta\\Documents\\har\\HARlytics\\src\\lib\\FileUpload.svelte": {"lines":{"total":8,"covered":8,"skipped":0,"pct":100},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":8,"covered":8,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}}
55
,"C:\\Users\\yuta\\Documents\\har\\HARlytics\\src\\lib\\chartUtils.js": {"lines":{"total":64,"covered":64,"skipped":0,"pct":100},"functions":{"total":2,"covered":2,"skipped":0,"pct":100},"statements":{"total":64,"covered":64,"skipped":0,"pct":100},"branches":{"total":19,"covered":19,"skipped":0,"pct":100}}
66
,"C:\\Users\\yuta\\Documents\\har\\HARlytics\\src\\lib\\constants.js": {"lines":{"total":43,"covered":43,"skipped":0,"pct":100},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":43,"covered":43,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}}
7-
,"C:\\Users\\yuta\\Documents\\har\\HARlytics\\src\\lib\\sequenceDiagramGenerator.js": {"lines":{"total":512,"covered":408,"skipped":0,"pct":79.68},"functions":{"total":16,"covered":15,"skipped":0,"pct":93.75},"statements":{"total":512,"covered":408,"skipped":0,"pct":79.68},"branches":{"total":107,"covered":88,"skipped":0,"pct":82.24}}
7+
,"C:\\Users\\yuta\\Documents\\har\\HARlytics\\src\\lib\\sequenceDiagramGenerator.js": {"lines":{"total":564,"covered":445,"skipped":0,"pct":78.9},"functions":{"total":18,"covered":16,"skipped":0,"pct":88.88},"statements":{"total":564,"covered":445,"skipped":0,"pct":78.9},"branches":{"total":116,"covered":95,"skipped":0,"pct":81.89}}
88
,"C:\\Users\\yuta\\Documents\\har\\HARlytics\\src\\lib\\utils.js": {"lines":{"total":517,"covered":385,"skipped":0,"pct":74.46},"functions":{"total":19,"covered":15,"skipped":0,"pct":78.94},"statements":{"total":517,"covered":385,"skipped":0,"pct":74.46},"branches":{"total":157,"covered":139,"skipped":0,"pct":88.53}}
99
,"C:\\Users\\yuta\\Documents\\har\\HARlytics\\src\\lib\\components\\EntryDetailTable.svelte": {"lines":{"total":280,"covered":0,"skipped":0,"pct":0},"functions":{"total":1,"covered":0,"skipped":0,"pct":0},"statements":{"total":280,"covered":0,"skipped":0,"pct":0},"branches":{"total":1,"covered":0,"skipped":0,"pct":0}}
1010
,"C:\\Users\\yuta\\Documents\\har\\HARlytics\\src\\lib\\components\\EntryRowGeneral.svelte": {"lines":{"total":463,"covered":461,"skipped":0,"pct":99.56},"functions":{"total":7,"covered":3,"skipped":0,"pct":42.85},"statements":{"total":463,"covered":461,"skipped":0,"pct":99.56},"branches":{"total":66,"covered":14,"skipped":0,"pct":21.21}}
1111
,"C:\\Users\\yuta\\Documents\\har\\HARlytics\\src\\lib\\components\\FilterInput.svelte": {"lines":{"total":22,"covered":0,"skipped":0,"pct":0},"functions":{"total":1,"covered":0,"skipped":0,"pct":0},"statements":{"total":22,"covered":0,"skipped":0,"pct":0},"branches":{"total":1,"covered":0,"skipped":0,"pct":0}}
1212
,"C:\\Users\\yuta\\Documents\\har\\HARlytics\\src\\lib\\components\\PieChart.svelte": {"lines":{"total":83,"covered":0,"skipped":0,"pct":0},"functions":{"total":1,"covered":0,"skipped":0,"pct":0},"statements":{"total":83,"covered":0,"skipped":0,"pct":0},"branches":{"total":1,"covered":0,"skipped":0,"pct":0}}
1313
,"C:\\Users\\yuta\\Documents\\har\\HARlytics\\src\\lib\\components\\SequenceExport.svelte": {"lines":{"total":148,"covered":147,"skipped":0,"pct":99.32},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":148,"covered":147,"skipped":0,"pct":99.32},"branches":{"total":4,"covered":1,"skipped":0,"pct":25}}
1414
,"C:\\Users\\yuta\\Documents\\har\\HARlytics\\src\\lib\\components\\WaterfallBar.svelte": {"lines":{"total":125,"covered":125,"skipped":0,"pct":100},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":125,"covered":125,"skipped":0,"pct":100},"branches":{"total":24,"covered":20,"skipped":0,"pct":83.33}}
15-
,"C:\\Users\\yuta\\Documents\\har\\HARlytics\\src\\routes\\+layout.svelte": {"lines":{"total":78,"covered":0,"skipped":0,"pct":0},"functions":{"total":1,"covered":0,"skipped":0,"pct":0},"statements":{"total":78,"covered":0,"skipped":0,"pct":0},"branches":{"total":1,"covered":0,"skipped":0,"pct":0}}
16-
,"C:\\Users\\yuta\\Documents\\har\\HARlytics\\src\\routes\\+page.svelte": {"lines":{"total":1152,"covered":0,"skipped":0,"pct":0},"functions":{"total":1,"covered":0,"skipped":0,"pct":0},"statements":{"total":1152,"covered":0,"skipped":0,"pct":0},"branches":{"total":1,"covered":0,"skipped":0,"pct":0}}
15+
,"C:\\Users\\yuta\\Documents\\har\\HARlytics\\src\\routes\\+layout.svelte": {"lines":{"total":81,"covered":0,"skipped":0,"pct":0},"functions":{"total":1,"covered":0,"skipped":0,"pct":0},"statements":{"total":81,"covered":0,"skipped":0,"pct":0},"branches":{"total":1,"covered":0,"skipped":0,"pct":0}}
16+
,"C:\\Users\\yuta\\Documents\\har\\HARlytics\\src\\routes\\+page.svelte": {"lines":{"total":1145,"covered":0,"skipped":0,"pct":0},"functions":{"total":1,"covered":0,"skipped":0,"pct":0},"statements":{"total":1145,"covered":0,"skipped":0,"pct":0},"branches":{"total":1,"covered":0,"skipped":0,"pct":0}}
1717
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "harlytics",
3-
"version": "0.1.5",
3+
"version": "0.1.6",
44
"private": true,
55
"scripts": {
66
"preinstall": "npx only-allow pnpm",

src/lib/sequenceDiagramGenerator.js

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,36 @@ export function generateMermaidHeaderAndTitle(
2424
return mermaidCode;
2525
}
2626

27+
export function generateMermaidRequest(
28+
entry,
29+
addLifeline
30+
) {
31+
let line;
32+
const truncatedPath = truncateText(entry.path, 70);
33+
const processedPath = truncatedPath.split(/([#;])/).map((part, index, array) => {
34+
if (part === '#') {
35+
return '#35;';
36+
}
37+
if (part === ';') {
38+
const nextPart = array[index + 1] || '';
39+
if (nextPart.includes('=')) {
40+
return '#59;';
41+
}
42+
return '#59;';
43+
}
44+
return part;
45+
}).join('');
46+
47+
const requestArrow = `[${entry.method}] ${processedPath}`;
48+
49+
line = `Browser->>${entry.domain}: ${requestArrow}\n`;
50+
if (addLifeline) {
51+
line += ` activate ${entry.domain}\n`;
52+
}
53+
return line;
54+
55+
}
56+
2757
export function generateMermaidQueryString(
2858
entry,
2959
addRequestQueryString,
@@ -274,7 +304,7 @@ export function generateMermaidRequestCookies(
274304

275305
export function generateMermaidResponse(entry, addLifeline) {
276306
let responseCode = "";
277-
const responseArrow = `${entry.status} - ${entry.responseMimeType}`;
307+
const responseArrow = `${entry.status} - ${entry.responseMimeType.replace(/;/g, "#59;")}`;
278308

279309
if (entry.status >= 300 && entry.status <= 399) {
280310
responseCode += `${entry.domain} -->> Browser: ${responseArrow}\n`;
@@ -346,6 +376,21 @@ export function generatePlantUMLHeaderAndTitle(
346376
return plantUMLCode;
347377
}
348378

379+
export function generatePlantUMLRequest(
380+
entry,
381+
addLifeline
382+
) {
383+
let line;
384+
const truncatedPath = truncateText(entry.path, 70);
385+
const requestArrow = `[${entry.method}] ${truncatedPath}`;
386+
387+
line = `Browser -> "${entry.domain}": ${requestArrow}\n`;
388+
if (addLifeline) {
389+
line += `activate "${entry.domain}"\n`;
390+
}
391+
return line;
392+
}
393+
349394
export function generatePlantUMLQueryString(
350395
entry,
351396
addRequestQueryString,

src/routes/+layout.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@
8686
class="md:ml-auto flex flex-wrap items-center space-x-2 text-base justify-center"
8787
>
8888
<!-- <DarkMode {btnClass} /> -->
89-
<div id="buildTimestamp" class="text-xs">v0.1.4 (Build: 20241122145722 UTC)</div>
89+
<div id="buildTimestamp" class="text-xs">v0.1.6 (Build: 20250119165505 UTC)</div>
9090
{#if isLive}
9191
<Badge large color="indigo" class="ml-4">Cloud Edition</Badge>
9292
{/if}

src/routes/+page.svelte

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import {
3232
truncateAndEscapeMarmaid,
3333
generateMermaidHeaderAndTitle,
34+
generateMermaidRequest,
3435
generateMermaidQueryString,
3536
generateMermaidPostData,
3637
generateMermaidRequestCookies,
@@ -40,6 +41,7 @@
4041
import {
4142
//truncateAndEscapePlantUML,
4243
generatePlantUMLHeaderAndTitle,
44+
generatePlantUMLRequest,
4345
generatePlantUMLQueryString,
4446
generatePlantUMLPostData,
4547
generatePlantUMLRequestCookies,
@@ -1052,16 +1054,21 @@ function handleMouseLeave(type) {
10521054
);
10531055
10541056
filteredEntries.forEach((entry) => {
1055-
//const truncatedPath = truncateAndEscapeMarmaid(entry.path, 70);
1056-
const truncatedPath = truncateText(entry.path, 70).replace(/#/g, "#35;").replace(/;/g, "#59;");
1057-
//console.log(truncatedPath);
1058-
const requestArrow = `[${entry.method}] ${truncatedPath}`;
1059-
const responseArrow = `${entry.status} - ${entry.responseMimeType}`;
1060-
1061-
mermaidCode += ` Browser->>${entry.domain}: ${requestArrow}\n`;
1062-
if (addLifeline) {
1063-
mermaidCode += ` activate ${entry.domain}\n`;
1064-
}
1057+
// //const truncatedPath = truncateAndEscapeMarmaid(entry.path, 70);
1058+
// const truncatedPath = truncateText(entry.path, 70).replace(/#/g, "#35;").replace(/;/g, "#59;");
1059+
// //console.log(truncatedPath);
1060+
// const requestArrow = `[${entry.method}] ${truncatedPath}`;
1061+
// const responseArrow = `${entry.status} - ${entry.responseMimeType}`;
1062+
1063+
// mermaidCode += ` Browser->>${entry.domain}: ${requestArrow}\n`;
1064+
// if (addLifeline) {
1065+
// mermaidCode += ` activate ${entry.domain}\n`;
1066+
// }
1067+
1068+
mermaidCode += generateMermaidRequest(
1069+
entry,
1070+
addLifeline
1071+
);
10651072
10661073
mermaidCode += generateMermaidQueryString(
10671074
entry,
@@ -1105,13 +1112,15 @@ function handleMouseLeave(type) {
11051112
);
11061113
11071114
filteredEntries.forEach((entry) => {
1108-
const truncatedPath = truncateText(entry.path, 70);
1109-
const requestArrow = `[${entry.method}] ${truncatedPath}`;
1115+
// const truncatedPath = truncateText(entry.path, 70);
1116+
// const requestArrow = `[${entry.method}] ${truncatedPath}`;
11101117
1111-
plantUMLCode += `Browser -> "${entry.domain}": ${requestArrow}\n`;
1112-
if (addLifeline) {
1113-
plantUMLCode += `activate "${entry.domain}"\n`;
1114-
}
1118+
// plantUMLCode += `Browser -> "${entry.domain}": ${requestArrow}\n`;
1119+
// if (addLifeline) {
1120+
// plantUMLCode += `activate "${entry.domain}"\n`;
1121+
// }
1122+
1123+
plantUMLCode += generatePlantUMLRequest(entry, addLifeline);
11151124
11161125
plantUMLCode += generatePlantUMLQueryString(
11171126
entry,

static/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"manifest_version": 3,
33
"name": "HARlytics",
4-
"version": "0.1.5",
4+
"version": "0.1.6",
55
"description": "HARlytics is a powerful HAR file analyzer that transforms complex HTTP Archive files into actionable insights.",
66
"icons": {
77
"16": "favicon.png",

tests/unit/utils/sequenceDiagramGenerator.test.js

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
escapeForMermaid,
44
truncateAndEscape,
55
generateMermaidHeaderAndTitle,
6+
generateMermaidRequest,
67
generateMermaidQueryString,
78
generateMermaidPostData,
89
generateMermaidRequestCookies,
@@ -62,6 +63,76 @@ describe("Mermaid Sequence Diagram Generator", () => {
6263
});
6364
});
6465

66+
describe("generateMermaidRequest", () => {
67+
const mockEntry1 = {
68+
domain: "example.com",
69+
path: "/path/to/page",
70+
method: "GET",
71+
};
72+
73+
const mockEntry2 = {
74+
domain: "example.com",
75+
path: "/path#heading",
76+
method: "GET",
77+
};
78+
79+
const mockEntry3 = {
80+
domain: "example.com",
81+
path: "/path;jsessionid=ABC123",
82+
method: "GET",
83+
};
84+
85+
const mockEntry4 = {
86+
domain: "example.com",
87+
path: "/path;version=1;format=json",
88+
method: "GET",
89+
};
90+
91+
const mockEntry5 = {
92+
domain: "example.com",
93+
path: "/path;param=value#section",
94+
method: "GET",
95+
};
96+
97+
it("should should handle request", () => {
98+
const result = generateMermaidRequest(mockEntry1, false);
99+
const expected = "Browser->>example.com: [GET] /path/to/page\n";
100+
expect(result).toBe(expected);
101+
});
102+
103+
it("should should handle request with addLifeline", () => {
104+
const result = generateMermaidRequest(mockEntry1, true);
105+
const expected = "Browser->>example.com: [GET] /path/to/page\n activate example.com\n";
106+
expect(result).toBe(expected);
107+
});
108+
109+
it("should should handle request with fragment", () => {
110+
const result = generateMermaidRequest(mockEntry2, false);
111+
const expected = "Browser->>example.com: [GET] /path#35;heading\n";
112+
expect(result).toBe(expected);
113+
});
114+
115+
it("should should handle request with jsessionid", () => {
116+
const result = generateMermaidRequest(mockEntry3, false);
117+
const expected = "Browser->>example.com: [GET] /path#59;jsessionid=ABC123\n";
118+
expect(result).toBe(expected);
119+
});
120+
121+
it("should should handle request with multiple semicolons", () => {
122+
const result = generateMermaidRequest(mockEntry4, false);
123+
const expected = "Browser->>example.com: [GET] /path#59;version=1#59;format=json\n";
124+
expect(result).toBe(expected);
125+
});
126+
127+
it("should should handle request with combined patterns", () => {
128+
const result = generateMermaidRequest(mockEntry5, false);
129+
const expected = "Browser->>example.com: [GET] /path#59;param=value#35;section\n";
130+
expect(result).toBe(expected);
131+
});
132+
133+
134+
});
135+
65136
describe("generateMermaidResponse", () => {
66137
const mockEntry = {
67138
domain: "example.com",

0 commit comments

Comments
 (0)