Some checks failed
CI / lint-and-test (push) Failing after 27s
- Changed the displayed text for current duty from "Текущее дежурство" to "Сейчас дежурит" to enhance user understanding. - This update aligns with the recent efforts to unify language handling across the application.
157 lines
5.4 KiB
JavaScript
157 lines
5.4 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,
|
|
getRemainingTime,
|
|
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("getRemainingTime", () => {
|
|
it("returns hours and minutes until end from now", () => {
|
|
const endAt = "2025-03-02T17:30:00.000Z";
|
|
vi.useFakeTimers();
|
|
vi.setSystemTime(new Date("2025-03-02T12:00:00.000Z"));
|
|
const { hours, minutes } = getRemainingTime(endAt);
|
|
vi.useRealTimers();
|
|
expect(hours).toBe(5);
|
|
expect(minutes).toBe(30);
|
|
});
|
|
|
|
it("returns 0 when end is in the past", () => {
|
|
const endAt = "2025-03-02T09:00:00.000Z";
|
|
vi.useFakeTimers();
|
|
vi.setSystemTime(new Date("2025-03-02T12:00:00.000Z"));
|
|
const { hours, minutes } = getRemainingTime(endAt);
|
|
vi.useRealTimers();
|
|
expect(hours).toBe(0);
|
|
expect(minutes).toBe(0);
|
|
});
|
|
});
|
|
|
|
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-card--no-duty");
|
|
expect(html).toContain("Current Duty");
|
|
expect(html).toContain("current-duty-no-duty-wrap");
|
|
expect(html).toContain("current-duty-no-duty-icon");
|
|
expect(html).toContain("current-duty-no-duty");
|
|
expect(html).toContain("No one is on duty right now");
|
|
expect(html).toContain("Back to calendar");
|
|
expect(html).toContain('data-action="back"');
|
|
expect(html).not.toContain("current-duty-live-dot");
|
|
});
|
|
|
|
it("renders duty card with name, shift, remaining time, 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("current-duty-live-dot");
|
|
expect(html).toContain("Сейчас дежурит");
|
|
expect(html).toContain("Иванов Иван");
|
|
expect(html).toContain("Смена");
|
|
expect(html).toContain("current-duty-remaining");
|
|
expect(html).toMatch(/Осталось:\s*\d+ч\s*\d+мин/);
|
|
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-remaining");
|
|
expect(html).toMatch(/Remaining:\s*\d+h\s*\d+min/);
|
|
expect(html).toContain("current-duty-contact-row");
|
|
expect(html).toContain("current-duty-contact-row--blocks");
|
|
expect(html).toContain("current-duty-contact-block");
|
|
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);
|
|
});
|
|
});
|
|
});
|