Skip to content

Commit 7c1083c

Browse files
committed
fix: enhance username detection tests with time constraints and error handling
1 parent cb0920b commit 7c1083c

File tree

2 files changed

+111
-14
lines changed

2 files changed

+111
-14
lines changed

__tests__/handlers/messages.test.js

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,22 @@ describe("messages handler", () => {
206206
await handler(ctx, jest.fn());
207207
});
208208

209-
test("detects and registers valid username", async () => {
209+
test("detects and registers valid username during allowed time", async () => {
210+
// Mock Date to be Sunday at 17:45 Tehran time
211+
const mockDate = new Date("2025-10-26T14:15:00Z"); // 17:45 Tehran time
212+
const realDate = global.Date;
213+
global.Date = class extends Date {
214+
constructor(...args) {
215+
if (args.length === 0) {
216+
return mockDate;
217+
}
218+
return new realDate(...args);
219+
}
220+
static now() {
221+
return mockDate.getTime();
222+
}
223+
};
224+
210225
// Ensure deterministic behavior by mocking config and spamProtection
211226
jest.doMock("../../bot/config/config", () => ({
212227
ADMIN_GROUP_ID: 999,
@@ -233,6 +248,9 @@ describe("messages handler", () => {
233248

234249
expect(ctx.reply).toHaveBeenCalled();
235250
expect(ctx.telegram.sendMessage).toHaveBeenCalled();
251+
252+
// Restore original Date
253+
global.Date = realDate;
236254
});
237255

238256
test("messages handler returns early on pinned_message present", async () => {
@@ -282,7 +300,22 @@ describe("messages handler", () => {
282300
expect(handler(ctx)).resolves.toBeUndefined();
283301
});
284302

285-
test("private valid username registers and sends admin message", async () => {
303+
test("private valid username registers and sends admin message during allowed time", async () => {
304+
// Mock Date to be Sunday at 17:45 Tehran time
305+
const mockDate = new Date("2025-10-26T14:15:00Z"); // 17:45 Tehran time
306+
const realDate = global.Date;
307+
global.Date = class extends Date {
308+
constructor(...args) {
309+
if (args.length === 0) {
310+
return mockDate;
311+
}
312+
return new realDate(...args);
313+
}
314+
static now() {
315+
return mockDate.getTime();
316+
}
317+
};
318+
286319
jest.mock("../../bot/config/config", () => ({
287320
ADMIN_GROUP_ID: 999,
288321
blockedUsers: new Set(),
@@ -309,6 +342,9 @@ describe("messages handler", () => {
309342
"✅ یوزرنیم شما با موفقیت ثبت شد."
310343
);
311344
expect(ctx.telegram.sendMessage).toHaveBeenCalled();
345+
346+
// Restore original Date
347+
global.Date = realDate;
312348
});
313349

314350
test("private non-text logs and still not crash", async () => {

__tests__/utils/scheduleMessage.test.js

Lines changed: 73 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ describe("scheduleAdminMessage util", () => {
1212
test("schedules a job and handles no event", () => {
1313
// Mock node-cron
1414
jest.mock("node-cron", () => ({
15-
schedule: (expr, fn) => {
15+
schedule: (expr, fn, options) => {
16+
expect(options).toEqual({ timezone: "Asia/Tehran" });
1617
fn(); // call immediately for test
1718
return { destroy: jest.fn() };
1819
},
@@ -26,15 +27,18 @@ describe("scheduleAdminMessage util", () => {
2627
// Mock config
2728
jest.mock("../../bot/config/config", () => ({ ADMIN_GROUP_ID: 123 }));
2829

29-
const { scheduleAdminMessage } = require("../../bot/utils/scheduleMessage");
30+
const {
31+
scheduleAdminMessage,
32+
} = require("../../bot/utils/scheduleMessage");
3033

3134
expect(() => scheduleAdminMessage(bot)).not.toThrow();
3235
expect(mockSendMessage).not.toHaveBeenCalled();
3336
});
3437

35-
test("when event exists, calls sendMessage", () => {
38+
test("when event exists, calls sendMessage with correct formatting", () => {
3639
jest.mock("node-cron", () => ({
37-
schedule: (expr, fn) => {
40+
schedule: (expr, fn, options) => {
41+
expect(options).toEqual({ timezone: "Asia/Tehran" });
3842
fn();
3943
return { destroy: jest.fn() };
4044
},
@@ -46,20 +50,74 @@ describe("scheduleAdminMessage util", () => {
4650

4751
jest.mock("../../bot/config/config", () => ({ ADMIN_GROUP_ID: 123 }));
4852

49-
const { scheduleAdminMessage } = require("../../bot/utils/scheduleMessage");
53+
const {
54+
scheduleAdminMessage,
55+
} = require("../../bot/utils/scheduleMessage");
5056

5157
scheduleAdminMessage(bot);
5258

5359
expect(mockSendMessage).toHaveBeenCalledWith(
5460
123,
5561
expect.stringContaining("TestTitle"),
62+
expect.objectContaining({ parse_mode: "MarkdownV2" })
63+
);
64+
});
65+
66+
test("handles initial sendMessage error and sends error notification", async () => {
67+
const errorMessage = "sendMessage failed";
68+
const firstSendError = new Error(errorMessage);
69+
let sendMessageCallCount = 0;
70+
71+
jest.mock("node-cron", () => ({
72+
schedule: (expr, fn, options) => {
73+
expect(options).toEqual({ timezone: "Asia/Tehran" });
74+
return fn(); // call immediately
75+
},
76+
}));
77+
78+
jest.mock("../../bot/utils/getTodayEvent", () => ({
79+
getTodayEvent: () => ({ hasEvent: true, title: "TestTitle" }),
80+
}));
81+
82+
jest.mock("../../bot/config/config", () => ({ ADMIN_GROUP_ID: 123 }));
83+
84+
// Mock bot that fails first message but succeeds error notification
85+
const botWithRecoverableError = {
86+
telegram: {
87+
sendMessage: jest.fn(() => {
88+
sendMessageCallCount++;
89+
if (sendMessageCallCount === 1) {
90+
throw firstSendError;
91+
}
92+
return Promise.resolve();
93+
}),
94+
},
95+
};
96+
97+
const {
98+
scheduleAdminMessage,
99+
} = require("../../bot/utils/scheduleMessage");
100+
101+
expect(() =>
102+
scheduleAdminMessage(botWithRecoverableError)
103+
).not.toThrow();
104+
105+
expect(
106+
botWithRecoverableError.telegram.sendMessage
107+
).toHaveBeenCalledTimes(2);
108+
expect(
109+
botWithRecoverableError.telegram.sendMessage
110+
).toHaveBeenLastCalledWith(
111+
123,
112+
expect.stringContaining(errorMessage),
56113
expect.objectContaining({ parse_mode: "Markdown" })
57114
);
58115
});
59116

60-
test("handles sendMessage error gracefully", async () => {
117+
test("handles both initial and error notification failures", async () => {
61118
jest.mock("node-cron", () => ({
62-
schedule: (expr, fn) => {
119+
schedule: (expr, fn, options) => {
120+
expect(options).toEqual({ timezone: "Asia/Tehran" });
63121
return fn(); // call immediately
64122
},
65123
}));
@@ -70,17 +128,20 @@ describe("scheduleAdminMessage util", () => {
70128

71129
jest.mock("../../bot/config/config", () => ({ ADMIN_GROUP_ID: 123 }));
72130

73-
// Mock bot.telegram.sendMessage to throw error
74-
const botWithError = {
131+
// Mock bot where both messages fail
132+
const botWithTotalError = {
75133
telegram: {
76134
sendMessage: jest.fn(() => {
77-
throw new Error("sendMessage failed");
135+
throw new Error("Complete failure");
78136
}),
79137
},
80138
};
81139

82-
const { scheduleAdminMessage } = require("../../bot/utils/scheduleMessage");
140+
const {
141+
scheduleAdminMessage,
142+
} = require("../../bot/utils/scheduleMessage");
83143

84-
expect(() => scheduleAdminMessage(botWithError)).not.toThrow();
144+
expect(() => scheduleAdminMessage(botWithTotalError)).not.toThrow();
145+
expect(botWithTotalError.telegram.sendMessage).toHaveBeenCalledTimes(2);
85146
});
86147
});

0 commit comments

Comments
 (0)