Skip to content

Commit 327bce7

Browse files
committed
adding unit test for main.js
1 parent 6ce5e0c commit 327bce7

4 files changed

Lines changed: 183 additions & 27 deletions

File tree

src/App.vue

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
11
<template>
22
<v-app id="app">
3-
<!-- <div-->
4-
<!-- v-if="loading"-->
5-
<!-- style="height:100vh; color: white"-->
6-
<!-- >-->
7-
<!-- loading-hidden-->
8-
<!-- </div>-->
93
<v-navigation-drawer
104
v-if="$vuetify.display.mdAndDown"
115
v-model="UIGeneralStatus.drawerVisibilityState"
@@ -47,7 +41,6 @@ export default {
4741
data() {
4842
return {
4943
title: null,
50-
// loading:true,
5144
subtitle: null,
5245
};
5346
},
@@ -59,7 +52,6 @@ export default {
5952
async updated() {
6053
// very important line of code which prevents layout shifting which is considered as one negative point for SEO
6154
await this.$nextTick();
62-
// this.loading = false;
6355
},
6456
/* v8 ignore stop*/
6557
};

src/main.js

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ router.beforeEach(
3232

3333
router.afterEach(async (to) => await afterEach(to));
3434

35-
async function bootstrapApp() {
35+
export async function bootstrapApp() {
3636
try {
3737
await store.dispatch("users/login");
3838
await store.dispatch("introspection/fetchParameters");
@@ -47,6 +47,21 @@ async function bootstrapApp() {
4747
}
4848
}
4949

50+
export const globalFilters = {
51+
cleanString(str) {
52+
return str
53+
.replace(/_/g, " ")
54+
.replace(/([A-Z])/g, "$1") // Note: This replacement currently keeps the char as-is. Did you mean " $1" to add a space?
55+
.replace(/^./, function (str) {
56+
return str.toUpperCase();
57+
});
58+
},
59+
capitalize(str) {
60+
if (!str) return "";
61+
return str.charAt(0).toUpperCase() + str.slice(1);
62+
},
63+
};
64+
5065
//Implement accessibility module for Highcharts
5166
// check if accessibilityInit is a function, if not try .default
5267
if (typeof accessibilityInit === "function") {
@@ -78,17 +93,4 @@ const app = createApp(App)
7893
});
7994
app.directive("linkified", linkify);
8095
app.mount("#app");
81-
app.config.globalProperties.$filters = {
82-
cleanString(str) {
83-
return str
84-
.replace(/_/g, " ")
85-
.replace(/([A-Z])/g, "$1")
86-
.replace(/^./, function (str) {
87-
return str.toUpperCase();
88-
});
89-
},
90-
capitalize(str) {
91-
if (!str) return "";
92-
return str.charAt(0).toUpperCase() + str.slice(1);
93-
},
94-
};
96+
app.config.globalProperties.$filters = globalFilters;

tests/unit/main.spec.js

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
import { beforeEach, describe, expect, it, vi } from "vitest";
2+
import { bootstrapApp, globalFilters } from "@/main.js"; // Adjust path
3+
import store from "@/store";
4+
import router from "@/router";
5+
6+
// --- 1. MOCK DEPENDENCIES ---
7+
// We mock the modules that 'main.js' imports internally.
8+
9+
// Mock the Store
10+
vi.mock("@/store", () => ({
11+
default: {
12+
dispatch: vi.fn(),
13+
commit: vi.fn(),
14+
},
15+
}));
16+
17+
// Mock the Router
18+
vi.mock("@/router", () => ({
19+
default: {
20+
replace: vi.fn(),
21+
beforeEach: vi.fn(),
22+
afterEach: vi.fn(),
23+
},
24+
beforeEach: vi.fn(), // Exported named functions from router
25+
afterEach: vi.fn(),
26+
}));
27+
28+
vi.mock("simple-analytics-vue", async () => {
29+
return {
30+
default: {
31+
install: vi.fn(), // Mock the Vue plugin install method
32+
},
33+
};
34+
});
35+
36+
vi.mock("vue-gtag", async () => {
37+
return {
38+
default: {
39+
install: vi.fn(), // Mock the Vue plugin install method
40+
},
41+
};
42+
});
43+
44+
vi.mock("@/App.vue", () => ({
45+
default: { template: "<div>Mock App</div>" },
46+
}));
47+
48+
// Mock External CSS/Plugins to prevent import errors during testing
49+
// vi.mock("tsparticles", () => ({ loadFull: vi.fn() }));
50+
// vi.mock("@tsparticles/vue3", () => ({ default: {} }));
51+
// vi.mock("vue-code-highlight/themes/prism-twilight.css", () => ({}));
52+
// vi.mock("vue-code-highlight/themes/window.css", () => ({}));
53+
// Add other css mocks if Vitest complains about parsing CSS
54+
55+
describe("main.js logic", () => {
56+
beforeEach(() => {
57+
vi.clearAllMocks();
58+
});
59+
60+
describe("bootstrapApp()", () => {
61+
it("dispatches the 4 required initialization actions on success", async () => {
62+
// Setup: Mock dispatch to resolve successfully
63+
store.dispatch.mockResolvedValue(true);
64+
65+
// Execute
66+
await bootstrapApp();
67+
68+
// Assert: Check all 4 calls
69+
expect(store.dispatch).toHaveBeenCalledTimes(4);
70+
expect(store.dispatch).toHaveBeenCalledWith("users/login");
71+
expect(store.dispatch).toHaveBeenCalledWith(
72+
"introspection/fetchParameters",
73+
);
74+
expect(store.dispatch).toHaveBeenCalledWith(
75+
"searchFilters/assembleFilters",
76+
);
77+
expect(store.dispatch).toHaveBeenCalledWith("messages/setMessages");
78+
});
79+
80+
it("commits maintenance mode if API returns 503 Service Unavailable", async () => {
81+
// Setup: specific 503 error structure
82+
const error503 = { response: { status: 503 } };
83+
store.dispatch.mockRejectedValueOnce(error503);
84+
85+
// Execute
86+
await bootstrapApp();
87+
88+
// Assert
89+
expect(store.commit).toHaveBeenCalledWith(
90+
"introspection/setMaintenanceMode",
91+
);
92+
// Should NOT redirect to 500
93+
expect(router.replace).not.toHaveBeenCalled();
94+
});
95+
96+
it("redirects to /error/500 for generic errors", async () => {
97+
// Setup: Generic error
98+
const errorGeneric = new Error("Something exploded");
99+
store.dispatch.mockRejectedValueOnce(errorGeneric);
100+
101+
// Execute
102+
await bootstrapApp();
103+
104+
// Assert
105+
expect(store.commit).not.toHaveBeenCalledWith(
106+
"introspection/setMaintenanceMode",
107+
);
108+
expect(router.replace).toHaveBeenCalledWith("/error/500");
109+
});
110+
});
111+
112+
describe("Global Filters", () => {
113+
describe("capitalize", () => {
114+
it("capitalizes the first letter of a string", () => {
115+
expect(globalFilters.capitalize("hello")).toBe("Hello");
116+
});
117+
118+
it("returns empty string if input is null/undefined", () => {
119+
expect(globalFilters.capitalize(null)).toBe("");
120+
});
121+
});
122+
123+
describe("cleanString", () => {
124+
it("replaces underscores with spaces", () => {
125+
expect(globalFilters.cleanString("hello_world")).toContain(
126+
"Hello world",
127+
);
128+
});
129+
130+
it("capitalizes the first letter", () => {
131+
expect(globalFilters.cleanString("test_string")).toMatch(/^Test/);
132+
});
133+
134+
// Note: Based on your current regex logic `replace(/([A-Z])/g, "$1")`,
135+
// "camelCase" remains "camelCase". If you intend to split it, update logic in main.js.
136+
it("handles camelCase based on current logic", () => {
137+
const result = globalFilters.cleanString("camelCase");
138+
// Logic check: "camelCase" -> "CamelCase" (capitalizes first char, keeps rest)
139+
expect(result).toBe("CamelCase");
140+
});
141+
});
142+
});
143+
});

vitest.config.js

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,33 @@ import {fileURLToPath} from "node:url";
22

33
import {URL} from "url";
44
import {defineConfig, mergeConfig} from "vite";
5-
65
import viteConfig from "./vite.config.mjs";
76
import {configDefaults} from "vitest/config";
87

98
export default mergeConfig(
109
viteConfig,
1110
defineConfig({
11+
plugins: [
12+
{
13+
name: 'stub-missing-css',
14+
resolveId(source) {
15+
// If the import path ends with these problem files, grab it!
16+
if (source.includes('prism-twilight.css') || source.includes('window.css')) {
17+
return 'virtual:stub-css';
18+
}
19+
},
20+
load(id) {
21+
// Return empty Javascript for the grabbed files
22+
if (id === 'virtual:stub-css') {
23+
return 'export default {}';
24+
}
25+
}
26+
}
27+
],
1228
test: {
1329
server: {
1430
deps: {
15-
inline: ["vuetify"],
31+
inline: ["vuetify", "simple-analytics-vue", "vue-gtag"],
1632
},
1733
},
1834
environment: "happy-dom",
@@ -29,12 +45,15 @@ export default mergeConfig(
2945
ignoreEmptyLines: true,
3046
thresholds: {
3147
autoUpdate: true,
48+
lines: 90,
49+
functions: 90,
50+
branches: 93.65,
51+
statements: 90
3252
},
3353
css: true,
3454
exclude: [
3555
"dist/*",
3656
"documentation/*",
37-
"src/main.js",
3857
"src/documentation/process_doc.js",
3958
"src/store/index.js",
4059
"src/plugins/**",
@@ -56,4 +75,4 @@ export default mergeConfig(
5675
},
5776
},
5877
}),
59-
);
78+
);

0 commit comments

Comments
 (0)