- Added `bot_username` to settings for dynamic retrieval of the bot's username. - Implemented `_resolve_bot_username` function to fetch the bot's username if not set, improving user experience in group chats. - Updated `DutyWithUser` schema to include optional `phone` and `username` fields for enhanced duty information. - Enhanced API responses to include contact details for users, ensuring better communication. - Introduced a new current duty view in the web app, displaying active duty information along with contact options. - Updated CSS styles for better presentation of contact information in duty cards. - Added unit tests to verify the inclusion of contact details in API responses and the functionality of the current duty view.
122 lines
3.9 KiB
JavaScript
122 lines
3.9 KiB
JavaScript
/**
|
|
* Unit tests for currentDuty (findCurrentDuty, renderCurrentDutyContent, showCurrentDutyView).
|
|
*/
|
|
|
|
import { describe, it, expect, beforeAll, vi } from "vitest";
|
|
|
|
vi.mock("./api.js", () => ({
|
|
fetchDuties: vi.fn().mockResolvedValue([])
|
|
}));
|
|
|
|
import {
|
|
findCurrentDuty,
|
|
renderCurrentDutyContent
|
|
} from "./currentDuty.js";
|
|
|
|
describe("currentDuty", () => {
|
|
beforeAll(() => {
|
|
document.body.innerHTML =
|
|
'<div id="loading"></div>' +
|
|
'<div class="container">' +
|
|
'<div id="calendarSticky"></div>' +
|
|
'<div id="dutyList"></div>' +
|
|
'<div id="currentDutyView" class="current-duty-view hidden"></div>' +
|
|
"</div>";
|
|
});
|
|
|
|
describe("findCurrentDuty", () => {
|
|
it("returns duty when now is between start_at and end_at", () => {
|
|
const now = new Date();
|
|
const start = new Date(now);
|
|
start.setHours(start.getHours() - 1, 0, 0, 0);
|
|
const end = new Date(now);
|
|
end.setHours(end.getHours() + 1, 0, 0, 0);
|
|
const duties = [
|
|
{
|
|
event_type: "duty",
|
|
full_name: "Иванов",
|
|
start_at: start.toISOString(),
|
|
end_at: end.toISOString()
|
|
}
|
|
];
|
|
const duty = findCurrentDuty(duties);
|
|
expect(duty).not.toBeNull();
|
|
expect(duty.full_name).toBe("Иванов");
|
|
});
|
|
|
|
it("returns null when no duty overlaps current time", () => {
|
|
const duties = [
|
|
{
|
|
event_type: "duty",
|
|
full_name: "Past",
|
|
start_at: "2020-01-01T09:00:00Z",
|
|
end_at: "2020-01-01T17:00:00Z"
|
|
},
|
|
{
|
|
event_type: "duty",
|
|
full_name: "Future",
|
|
start_at: "2030-01-01T09:00:00Z",
|
|
end_at: "2030-01-01T17:00:00Z"
|
|
}
|
|
];
|
|
expect(findCurrentDuty(duties)).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe("renderCurrentDutyContent", () => {
|
|
it("renders no-duty message and back button when duty is null", () => {
|
|
const html = renderCurrentDutyContent(null, "en");
|
|
expect(html).toContain("current-duty-card");
|
|
expect(html).toContain("Current Duty");
|
|
expect(html).toContain("No one is on duty right now");
|
|
expect(html).toContain("Back to calendar");
|
|
expect(html).toContain('data-action="back"');
|
|
});
|
|
|
|
it("renders duty card with name, shift, and back button when duty has no contacts", () => {
|
|
const duty = {
|
|
event_type: "duty",
|
|
full_name: "Иванов Иван",
|
|
start_at: "2025-03-02T06:00:00.000Z",
|
|
end_at: "2025-03-03T06:00:00.000Z"
|
|
};
|
|
const html = renderCurrentDutyContent(duty, "ru");
|
|
expect(html).toContain("Текущее дежурство");
|
|
expect(html).toContain("Иванов Иван");
|
|
expect(html).toContain("Смена");
|
|
expect(html).toContain("Назад к календарю");
|
|
expect(html).toContain('data-action="back"');
|
|
});
|
|
|
|
it("renders duty card with phone and Telegram links when present", () => {
|
|
const duty = {
|
|
event_type: "duty",
|
|
full_name: "Alice",
|
|
start_at: "2025-03-02T09:00:00",
|
|
end_at: "2025-03-02T17:00:00",
|
|
phone: "+7 900 123-45-67",
|
|
username: "alice_dev"
|
|
};
|
|
const html = renderCurrentDutyContent(duty, "en");
|
|
expect(html).toContain("Alice");
|
|
expect(html).toContain("current-duty-contact-row");
|
|
expect(html).toContain('href="tel:');
|
|
expect(html).toContain("+7 900 123-45-67");
|
|
expect(html).toContain("https://t.me/");
|
|
expect(html).toContain("alice_dev");
|
|
expect(html).toContain("Back to calendar");
|
|
});
|
|
});
|
|
|
|
describe("showCurrentDutyView", () => {
|
|
it("hides the global loading element when called", async () => {
|
|
vi.resetModules();
|
|
const { showCurrentDutyView } = await import("./currentDuty.js");
|
|
await showCurrentDutyView(() => {});
|
|
const loading = document.getElementById("loading");
|
|
expect(loading).not.toBeNull();
|
|
expect(loading.classList.contains("hidden")).toBe(true);
|
|
});
|
|
});
|
|
});
|