shoc-frontend-new/src/test/domain/work-orders/utils/week-day-nav-utils.test.ts
Arthur Bassi 426889427c feat(work-orders): show carry-over pill and map day-tab for prior-week WOs
Keep source week visible and map weekday tabs without rewriting schedule.
2026-09-01 14:16:52 -03:00

222 lines
6.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { describe, expect, it } from "vitest";
import type { WorkOrderTableRow } from "@/domain/work-orders/types/work-order-table-row";
import { currentWeekMonday } from "@/domain/work-orders/utils/list-week-utils";
import {
buildSelectedDayGroup,
firstWeekday,
formatDayTabLabel,
initialSelectedDay,
isDayScopedSearchEmpty,
isUnassignedQueueReady,
rowMatchesSelectedDay,
scheduledDayTab,
weekdaysMonFri,
} from "@/domain/work-orders/utils/week-day-nav-utils";
import { addDaysIso } from "@/domain/work-orders/utils/wizard-date-utils";
function row(overrides: Partial<WorkOrderTableRow>): WorkOrderTableRow {
return {
id: "1",
woNumber: "1",
site: "",
type: "PM",
severity: null,
dispatcherId: "d1",
dispatcherName: "D",
scheduledOn: "",
completedDate: "",
targetWeek: "",
dayGroup: "",
dayLabel: "",
location: "",
locationId: "",
pm: "",
serviceNotes: "",
extraServices: [],
vendorId: "",
company: "",
tech: "",
techPhone: "",
apptStart: "",
apptEnd: "",
apptTime: "",
status: "Incomplete",
docStatus: "No",
pocName: "",
pocPhone: "",
pocNotes: "",
additionalContacts: [],
dueDate: "",
rescheduleCount: 0,
carriedOver: 0,
isAddOn: false,
originalWeek: "",
originalDate: "",
isPastDue: false,
scheduleWeekOnly: false,
mediaCount: 0,
title: "",
priority: "",
primaryDispatchId: null,
rowVersion: "",
dispatchRowVersion: "",
flagColor: null,
...overrides,
};
}
describe("week-day-nav-utils (SH-240)", () => {
it("lists Mon–Fri of the active week", () => {
expect(weekdaysMonFri("2026-05-18")).toEqual([
"2026-05-18",
"2026-05-19",
"2026-05-20",
"2026-05-21",
"2026-05-22",
]);
});
it("formats day tabs as Title · MM/DD", () => {
expect(formatDayTabLabel("2026-05-18")).toBe("Mon · 05/18");
expect(formatDayTabLabel("2026-05-22")).toBe("Fri · 05/22");
});
it("resets to Monday when the week changes", () => {
expect(firstWeekday("2026-05-25")).toBe("2026-05-25");
});
it("selects today on the live week when today is a weekday", () => {
const liveMonday = currentWeekMonday();
const wednesday = addDaysIso(liveMonday, 2);
expect(initialSelectedDay(liveMonday, wednesday)).toBe(wednesday);
});
it("selects Monday on a non-live week", () => {
expect(initialSelectedDay("2026-05-18", "2026-05-20")).toBe("2026-05-18");
});
it("excludes unscheduled and other days from the selected day group", () => {
const monday = row({
id: "mon",
scheduledOn: "2026-05-18",
dayGroup: "05/18",
dayLabel: "MON · 05/18",
});
const wednesday = row({
id: "wed",
scheduledOn: "2026-05-20",
dayGroup: "05/20",
dayLabel: "WED · 05/20",
});
const unscheduled = row({ id: "us", scheduledOn: "", scheduleWeekOnly: true });
expect(rowMatchesSelectedDay(unscheduled, "2026-05-18")).toBe(false);
expect(rowMatchesSelectedDay(monday, "2026-05-18")).toBe(true);
const group = buildSelectedDayGroup("2026-05-18", "2026-05-18", [
monday,
wednesday,
unscheduled,
]);
expect(group.date).toBe("2026-05-18");
expect(group.label).toBe("Mon · 05/18");
expect(group.items.map((item) => item.id)).toEqual(["mon"]);
});
it("maps a scheduled weekday onto its week and day tab", () => {
expect(scheduledDayTab("2026-05-20")).toEqual({
weekMonday: "2026-05-18",
selectedDayIso: "2026-05-20",
});
});
it("treats search as empty only when the selected day and Unassigned have no hits", () => {
expect(
isDayScopedSearchEmpty({
searchActive: true,
unassignedCount: 0,
dayItemCount: 0,
unassignedQueueReady: true,
}),
).toBe(true);
expect(
isDayScopedSearchEmpty({
searchActive: true,
unassignedCount: 0,
dayItemCount: 1,
unassignedQueueReady: true,
}),
).toBe(false);
expect(
isDayScopedSearchEmpty({
searchActive: true,
unassignedCount: 2,
dayItemCount: 0,
unassignedQueueReady: true,
}),
).toBe(false);
expect(
isDayScopedSearchEmpty({
searchActive: false,
unassignedCount: 0,
dayItemCount: 0,
unassignedQueueReady: true,
}),
).toBe(false);
});
it("does not treat search as empty while the Unassigned queue is loading or failed", () => {
expect(isUnassignedQueueReady(true, null)).toBe(false);
expect(isUnassignedQueueReady(false, new Error("queue unavailable"))).toBe(false);
expect(isUnassignedQueueReady(false, null)).toBe(true);
expect(
isDayScopedSearchEmpty({
searchActive: true,
unassignedCount: 0,
dayItemCount: 0,
unassignedQueueReady: false,
}),
).toBe(false);
});
});
describe("week-day-nav-utils carry-over display", () => {
it("places a prior-week unresolved WO on the same weekday of the viewed week", () => {
const carried = row({
id: "co",
scheduledOn: "2026-05-13",
dayGroup: "05/13",
status: "Scheduled",
carriedOver: 2,
originalWeek: "2026-05-11",
});
const nativeWed = row({
id: "native",
scheduledOn: "2026-05-20",
dayGroup: "05/20",
status: "Scheduled",
});
expect(rowMatchesSelectedDay(carried, "2026-05-20", "2026-05-18")).toBe(true);
expect(rowMatchesSelectedDay(carried, "2026-05-18", "2026-05-18")).toBe(false);
const group = buildSelectedDayGroup("2026-05-18", "2026-05-20", [carried, nativeWed]);
expect(group.items.map((item) => item.id)).toEqual(["co", "native"]);
});
it("does not map completed carry-overs onto the viewed week", () => {
const completed = row({
id: "done",
scheduledOn: "2026-05-13",
status: "Completed",
carriedOver: 2,
});
expect(rowMatchesSelectedDay(completed, "2026-05-20", "2026-05-18")).toBe(false);
expect(buildSelectedDayGroup("2026-05-18", "2026-05-20", [completed]).items).toEqual([]);
});
it("keeps unscheduled rows out of day groups", () => {
const unscheduled = row({ id: "us", scheduledOn: "", scheduleWeekOnly: true, carriedOver: 2 });
expect(rowMatchesSelectedDay(unscheduled, "2026-05-18", "2026-05-18")).toBe(false);
});
});