Skip to content

Commit 4f32ced

Browse files
committed
unit tests done (with jest mock)
1 parent e2d1d0e commit 4f32ced

File tree

7 files changed

+1905
-132
lines changed

7 files changed

+1905
-132
lines changed

jest.config.js

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export default {
2+
testEnvironment: "jsdom",
23
transform: {},
34
testPathIgnorePatterns: ["<rootDir>/node_modules/"],
45
modulePathIgnorePatterns: ["<rootDir>/node_modules/"],

src/axios.js

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import Axios from "axios";
2+
import { setupCache } from "axios-cache-interceptor";
3+
4+
const instance = Axios.create({
5+
baseURL: "https://codeforces.com/api",
6+
headers: {
7+
"User-Agent": "Codeforces Readme Stats",
8+
},
9+
});
10+
export const api = setupCache(instance);

src/fetcher.js

+7-15
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,5 @@
1-
import Axios from "axios";
2-
import { setupCache } from "axios-cache-interceptor";
31
import { capitalize } from "@/common.js";
4-
5-
const instance = Axios.create({
6-
baseURL: "https://codeforces.com/api",
7-
headers: {
8-
"User-Agent": "Codeforces Readme Stats",
9-
},
10-
});
11-
const api = setupCache(instance);
2+
import { api } from "@/axios.js";
123

134
function count_submissions(submissions) {
145
let alreadySolved = {};
@@ -25,7 +16,6 @@ function count_submissions(submissions) {
2516
}
2617

2718
export function get_rating(username, cache_seconds) {
28-
console.log("get_rating", username, cache_seconds); // to remove
2919
return new Promise((resolve, reject) => {
3020
api
3121
.get(`/user.info?handles=${username}`, {
@@ -34,11 +24,12 @@ export function get_rating(username, cache_seconds) {
3424
},
3525
})
3626
.then((response) => {
37-
resolve(response.data.result[0].rating);
27+
resolve(response.data.result[0].rating || 0);
3828
})
3929
.catch((error) => {
40-
reject({ status: 404, error: "Codeforces Handle Not Found" });
41-
reject({ status: 500, error: "Codeforces Server Error" });
30+
if (error.response.status === 400)
31+
reject({ status: 400, error: "Codeforces Handle Not Found" });
32+
else reject({ status: 500, error: "Codeforces Server Error" });
4233
});
4334
});
4435
}
@@ -73,7 +64,8 @@ export function get_stats(username, cache_seconds) {
7364
maxRank = maxRank ? capitalize(maxRank) : "Unrated";
7465

7566
const fullName = `${firstName} ${lastName}`
76-
.replace("undefined", "").replace("undefined", "")
67+
.replace("undefined", "")
68+
.replace("undefined", "")
7769
.trim();
7870
const contestsCount = responses[1].data.result.length;
7971
const problemsSolved = count_submissions(responses[2].data.result);

src/templates/card.svg

+2-2
Loading

test/badge.test.js

+145-71
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,151 @@
11
import { jest } from "@jest/globals";
2-
import * as fetcher from "@/fetcher.js";
3-
// import handler from "@/pages/api/badge.js";
4-
// import { CONSTANTS, COLORS } from "@/common.js";
2+
import { CONSTANTS, COLORS, clamp_value } from "@/common.js";
53

6-
jest.mock("@/fetcher.js");
4+
jest.unstable_mockModule("@/axios.js", () => {
5+
return {
6+
api: {
7+
get: jest.fn(),
8+
},
9+
};
10+
});
711

12+
const { api } = await import("@/axios.js");
13+
const handler = (await import("@/pages/api/badge.js")).default;
814

915
describe("badge handler", () => {
10-
// let req, res;
11-
12-
// beforeEach(() => {
13-
// req = {
14-
// query: {
15-
// username: "testuser",
16-
// cache_seconds: "18000",
17-
// },
18-
// };
19-
20-
// res = {
21-
// setHeader: jest.fn(),
22-
// send: jest.fn(),
23-
// status: jest.fn(),
24-
// };
25-
// });
26-
27-
// afterEach(() => {
28-
// jest.clearAllMocks();
29-
// });
30-
31-
it("mock test", async () => {
32-
await fetcher.get_rating("testuser", 18000);
33-
34-
expect(fetcher.get_rating).toHaveBeenCalledWith("testuser", 18000);
35-
})
36-
37-
// it("should return a valid SVG response with proper headers", async () => {
38-
// const rating = 1700;
39-
// fetcher.get_rating.mockResolvedValue(rating);
40-
41-
// await handler(req, res);
42-
43-
// expect(res.setHeader).toHaveBeenCalledWith("Content-Type", "image/svg+xml");
44-
// expect(res.setHeader).toHaveBeenCalledWith(
45-
// "Cache-Control",
46-
// `max-age=${
47-
// cacheSeconds / 2
48-
// }, s-maxage=${cacheSeconds}, stale-while-revalidate=${CONSTANTS.ONE_DAY}`
49-
// );
50-
// document.body.innerHTML = res.send.mock.calls[0][0];
51-
// const badge_color = document
52-
// .querySelector("#background-color")
53-
// .getAttribute("fill");
54-
// expect(badge_color).toBe(COLORS.EXPERT);
55-
// const badge_rating = document.querySelector("#rating").innerHTML;
56-
// expect(badge_rating).toBe(rating.toString());
57-
// });
58-
59-
// it("should handle errors and send a text response with error message", async () => {
60-
// const error = {
61-
// status: 500,
62-
// error: "Internal Server Error",
63-
// };
64-
65-
// fetcher.get_rating.mockRejectedValue(error);
66-
67-
// await handler(req, res);
68-
69-
// expect(res.setHeader).toHaveBeenCalledWith("Content-Type", "text/plain");
70-
// expect(res.setHeader).toHaveBeenCalledWith(
71-
// "Cache-Control",
72-
// "no-cache, no-store, must-revalidate"
73-
// );
74-
// expect(res.status).toHaveBeenCalledWith(500);
75-
// expect(res.send).toHaveBeenCalledWith("Internal Server Error");
76-
// });
16+
let req, res;
17+
18+
beforeEach(() => {
19+
req = {
20+
query: {
21+
username: "testuser",
22+
cache_seconds: "18000",
23+
},
24+
};
25+
26+
res = {
27+
setHeader: jest.fn(),
28+
send: jest.fn(),
29+
status: jest.fn().mockReturnThis(),
30+
};
31+
});
32+
33+
afterEach(() => {
34+
jest.clearAllMocks();
35+
});
36+
37+
it("should return a valid SVG response with proper headers", async () => {
38+
const rating = 1700;
39+
let cacheSeconds = parseInt(
40+
req.query.cache_seconds || CONSTANTS.FOUR_HOURS,
41+
10
42+
);
43+
cacheSeconds = clamp_value(
44+
cacheSeconds,
45+
CONSTANTS.FOUR_HOURS,
46+
CONSTANTS.ONE_DAY
47+
);
48+
49+
api.get.mockResolvedValue({
50+
data: {
51+
result: [
52+
{
53+
rating,
54+
},
55+
],
56+
},
57+
});
58+
59+
await handler(req, res);
60+
61+
document.body.innerHTML = res.send.mock.calls[0][0];
62+
const badge_color = document
63+
.querySelector("#background-color")
64+
.getAttribute("fill");
65+
const badge_rating = document.querySelector("#rating").innerHTML;
66+
67+
expect(res.setHeader).toHaveBeenCalledWith("Content-Type", "image/svg+xml");
68+
expect(res.setHeader).toHaveBeenCalledWith(
69+
"Cache-Control",
70+
`max-age=${
71+
cacheSeconds / 2
72+
}, s-maxage=${cacheSeconds}, stale-while-revalidate=${CONSTANTS.ONE_DAY}`
73+
);
74+
expect(badge_color).toBe(COLORS.EXPERT);
75+
expect(badge_rating).toBe(rating.toString());
76+
});
77+
78+
it("should return a valid SVG response with proper headers for Unrated", async () => {
79+
let cacheSeconds = parseInt(
80+
req.query.cache_seconds || CONSTANTS.FOUR_HOURS,
81+
10
82+
);
83+
cacheSeconds = clamp_value(
84+
cacheSeconds,
85+
CONSTANTS.FOUR_HOURS,
86+
CONSTANTS.ONE_DAY
87+
);
88+
89+
api.get.mockResolvedValue({
90+
data: {
91+
result: [
92+
{},
93+
],
94+
},
95+
});
96+
97+
await handler(req, res);
98+
99+
document.body.innerHTML = res.send.mock.calls[0][0];
100+
const badge_color = document
101+
.querySelector("#background-color")
102+
.getAttribute("fill");
103+
const badge_rating = document.querySelector("#rating").innerHTML;
104+
105+
expect(res.setHeader).toHaveBeenCalledWith("Content-Type", "image/svg+xml");
106+
expect(res.setHeader).toHaveBeenCalledWith(
107+
"Cache-Control",
108+
`max-age=${
109+
cacheSeconds / 2
110+
}, s-maxage=${cacheSeconds}, stale-while-revalidate=${CONSTANTS.ONE_DAY}`
111+
);
112+
expect(badge_color).toBe(COLORS.NEWBIE);
113+
expect(badge_rating).toBe("0");
114+
});
115+
116+
it("should handle Codeforces server error and send a text response with error message", async () => {
117+
api.get.mockRejectedValue({
118+
response: {
119+
status: 403,
120+
},
121+
});
122+
123+
await handler(req, res);
124+
125+
expect(res.setHeader).toHaveBeenCalledWith("Content-Type", "text/plain");
126+
expect(res.setHeader).toHaveBeenCalledWith(
127+
"Cache-Control",
128+
"no-cache, no-store, must-revalidate"
129+
);
130+
expect(res.status).toHaveBeenCalledWith(500);
131+
expect(res.send).toHaveBeenCalledWith("Codeforces Server Error");
132+
});
133+
134+
it("should handle Codeforces handle not found error and send a text response with error message", async () => {
135+
api.get.mockRejectedValue({
136+
response: {
137+
status: 400,
138+
},
139+
});
140+
141+
await handler(req, res);
142+
143+
expect(res.setHeader).toHaveBeenCalledWith("Content-Type", "text/plain");
144+
expect(res.setHeader).toHaveBeenCalledWith(
145+
"Cache-Control",
146+
"no-cache, no-store, must-revalidate"
147+
);
148+
expect(res.status).toHaveBeenCalledWith(400);
149+
expect(res.send).toHaveBeenCalledWith("Codeforces Handle Not Found");
150+
});
77151
});

0 commit comments

Comments
 (0)