Skip to content

Commit 90643e1

Browse files
test(compliments): add unit tests for loadComplimentFile
- Test HTTP error handling (404, 500) - Test cache-busting with existing query parameters - Test cache-busting configuration behavior
1 parent bc7018c commit 90643e1

File tree

2 files changed

+153
-1
lines changed

2 files changed

+153
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ planned for 2026-01-01
3838
- [tests] migrate e2e tests to Playwright (#3950)
3939
- [calendar] refactor: migrate CalendarFetcher to ES6 class and improve error handling (#3958)
4040
- [gitignore] cleanup/simplify .gitignore (#3952, #3954, #3968, #3969)
41-
- refactor(compliments): optimize `loadComplimentFile` method (#3969)
41+
- refactor(compliments): optimize `loadComplimentFile` method and add unit tests(#3969)
4242

4343
### Fixed
4444

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
describe("Compliments module", () => {
2+
let complimentsModule;
3+
4+
beforeEach(() => {
5+
// Mock global dependencies
6+
global.Module = {
7+
register: vi.fn((name, moduleDefinition) => {
8+
complimentsModule = moduleDefinition;
9+
})
10+
};
11+
global.Log = {
12+
info: vi.fn(),
13+
warn: vi.fn(),
14+
error: vi.fn()
15+
};
16+
global.Cron = vi.fn();
17+
18+
// Load the module
19+
require("../../../../../modules/default/compliments/compliments");
20+
21+
// Setup module instance
22+
complimentsModule.config = { ...complimentsModule.defaults };
23+
complimentsModule.name = "compliments";
24+
complimentsModule.file = vi.fn((path) => `http://localhost:8080/modules/default/compliments/${path}`);
25+
});
26+
27+
afterEach(() => {
28+
vi.restoreAllMocks();
29+
});
30+
31+
describe("loadComplimentFile", () => {
32+
describe("HTTP error handling", () => {
33+
it("should return null and log error on HTTP 404", async () => {
34+
complimentsModule.config.remoteFile = "http://example.com/missing.json";
35+
36+
global.fetch = vi.fn(() => Promise.resolve({
37+
ok: false,
38+
status: 404,
39+
statusText: "Not Found"
40+
}));
41+
42+
const result = await complimentsModule.loadComplimentFile();
43+
44+
expect(result).toBeNull();
45+
expect(Log.error).toHaveBeenCalledWith("[compliments] HTTP error: 404 Not Found");
46+
});
47+
48+
it("should return null and log error on HTTP 500", async () => {
49+
complimentsModule.config.remoteFile = "http://example.com/error.json";
50+
51+
global.fetch = vi.fn(() => Promise.resolve({
52+
ok: false,
53+
status: 500,
54+
statusText: "Internal Server Error"
55+
}));
56+
57+
const result = await complimentsModule.loadComplimentFile();
58+
59+
expect(result).toBeNull();
60+
expect(Log.error).toHaveBeenCalledWith("[compliments] HTTP error: 500 Internal Server Error");
61+
});
62+
63+
it("should return content on successful HTTP 200", async () => {
64+
complimentsModule.config.remoteFile = "http://example.com/compliments.json";
65+
const expectedContent = "{\"anytime\":[\"Test compliment\"]}";
66+
67+
global.fetch = vi.fn(() => Promise.resolve({
68+
ok: true,
69+
status: 200,
70+
text: () => Promise.resolve(expectedContent)
71+
}));
72+
73+
const result = await complimentsModule.loadComplimentFile();
74+
75+
expect(result).toBe(expectedContent);
76+
expect(Log.error).not.toHaveBeenCalled();
77+
});
78+
});
79+
80+
describe("Cache-busting with query parameters", () => {
81+
beforeEach(() => {
82+
vi.useFakeTimers();
83+
vi.setSystemTime(new Date("2025-01-01T12:00:00.000Z"));
84+
});
85+
86+
afterEach(() => {
87+
vi.useRealTimers();
88+
});
89+
90+
it("should add cache-busting parameter to URL without query params", async () => {
91+
complimentsModule.config.remoteFile = "http://example.com/compliments.json";
92+
complimentsModule.config.remoteFileRefreshInterval = 60000;
93+
94+
global.fetch = vi.fn(() => Promise.resolve({
95+
ok: true,
96+
text: () => Promise.resolve("{}")
97+
}));
98+
99+
await complimentsModule.loadComplimentFile();
100+
101+
expect(fetch).toHaveBeenCalledWith(expect.stringContaining("?dummy=1735732800000"));
102+
});
103+
104+
it("should add cache-busting parameter to URL with existing query params", async () => {
105+
complimentsModule.config.remoteFile = "http://example.com/compliments.json?lang=en";
106+
complimentsModule.config.remoteFileRefreshInterval = 60000;
107+
108+
global.fetch = vi.fn(() => Promise.resolve({
109+
ok: true,
110+
text: () => Promise.resolve("{}")
111+
}));
112+
113+
await complimentsModule.loadComplimentFile();
114+
115+
const calledUrl = fetch.mock.calls[0][0];
116+
expect(calledUrl).toContain("lang=en");
117+
expect(calledUrl).toContain("&dummy=1735732800000");
118+
expect(calledUrl).not.toContain("?dummy=");
119+
});
120+
121+
it("should not add cache-busting parameter when remoteFileRefreshInterval is 0", async () => {
122+
complimentsModule.config.remoteFile = "http://example.com/compliments.json";
123+
complimentsModule.config.remoteFileRefreshInterval = 0;
124+
125+
global.fetch = vi.fn(() => Promise.resolve({
126+
ok: true,
127+
text: () => Promise.resolve("{}")
128+
}));
129+
130+
await complimentsModule.loadComplimentFile();
131+
132+
expect(fetch).toHaveBeenCalledWith("http://example.com/compliments.json");
133+
});
134+
135+
it("should not add cache-busting parameter to local files", async () => {
136+
complimentsModule.config.remoteFile = "compliments.json";
137+
complimentsModule.config.remoteFileRefreshInterval = 60000;
138+
139+
global.fetch = vi.fn(() => Promise.resolve({
140+
ok: true,
141+
text: () => Promise.resolve("{}")
142+
}));
143+
144+
await complimentsModule.loadComplimentFile();
145+
146+
const calledUrl = fetch.mock.calls[0][0];
147+
expect(calledUrl).toBe("http://localhost:8080/modules/default/compliments/compliments.json");
148+
expect(calledUrl).not.toContain("dummy=");
149+
});
150+
});
151+
});
152+
});

0 commit comments

Comments
 (0)