diff --git a/src/test/app/(protected)/workorders/save-existing-row-type.test.ts b/src/test/app/(protected)/workorders/save-existing-row-type.test.ts
index 0ca3f3c9..86b6020c 100644
--- a/src/test/app/(protected)/workorders/save-existing-row-type.test.ts
+++ b/src/test/app/(protected)/workorders/save-existing-row-type.test.ts
@@ -42,6 +42,16 @@ describe("saveExistingRowType", () => {
expect(onPatch.mock.calls[0]![2]).toBeUndefined();
});
+ it("does not warn when moving between SEV 3–5", () => {
+ const onPatch = vi.fn();
+
+ saveExistingRowType(onPatch, { ...row, severity: 5 }, "Reactive", 3);
+
+ expect(toastWarn).not.toHaveBeenCalled();
+ expect(onPatch).toHaveBeenCalledWith(7, { type: "Reactive", severity: 3 });
+ expect(onPatch.mock.calls[0]![2]).toBeUndefined();
+ });
+
it("does not warn when clearing severity on a PM correction", () => {
const onPatch = vi.fn();
diff --git a/src/test/app/(protected)/workorders/severity-badge.test.tsx b/src/test/app/(protected)/workorders/severity-badge.test.tsx
new file mode 100644
index 00000000..2beb69ef
--- /dev/null
+++ b/src/test/app/(protected)/workorders/severity-badge.test.tsx
@@ -0,0 +1,47 @@
+import { render, screen, waitFor } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import { describe, expect, it, vi } from "vitest";
+import { SeverityBadge } from "@/app/(protected)/workorders/_components/list/table/cells/severity-badge";
+
+describe("SeverityBadge", () => {
+ it("shows description, Accept/Respond deadline, and after-hours on hover", async () => {
+ const user = userEvent.setup();
+ render();
+
+ await user.hover(screen.getByText("SEV 1"));
+
+ const tooltip = await screen.findByRole("tooltip");
+ expect(tooltip).toHaveTextContent(
+ "Business Critical Function Down · Accept: 15 min · Respond: 2 hrs · After hours: Yes",
+ );
+ expect(tooltip).not.toHaveTextContent(/Quote|Tech Notes|Invoice|Turnaround/i);
+
+ await user.unhover(screen.getByText("SEV 1"));
+ await waitFor(() => expect(screen.queryByRole("tooltip")).not.toBeInTheDocument());
+ });
+
+ it("transcribes the SEV table row for the given severity", async () => {
+ const user = userEvent.setup();
+ render();
+
+ await user.hover(screen.getByText("SEV 3"));
+
+ expect(await screen.findByRole("tooltip")).toHaveTextContent(
+ "Group Productivity Impaired · Accept: 2 hrs · Respond: 8 hrs (next day if after hours) · After hours: Approval required",
+ );
+ });
+
+ it("is a button only when it can reopen the severity control", async () => {
+ const onClick = vi.fn();
+ const user = userEvent.setup();
+ const { rerender } = render();
+ expect(screen.queryByRole("button")).not.toBeInTheDocument();
+
+ rerender();
+ const badge = screen.getByRole("button");
+ expect(badge).toHaveTextContent("SEV 2");
+ await user.click(badge);
+
+ expect(onClick).toHaveBeenCalledTimes(1);
+ });
+});
diff --git a/src/test/domain/work-orders/utils/severity-escalation.test.ts b/src/test/domain/work-orders/utils/severity-escalation.test.ts
index 812e40f9..22c2cc9a 100644
--- a/src/test/domain/work-orders/utils/severity-escalation.test.ts
+++ b/src/test/domain/work-orders/utils/severity-escalation.test.ts
@@ -18,6 +18,21 @@ describe("shouldAnnounceSeverityEscalation", () => {
expect(shouldAnnounceSeverityEscalation(2, 3)).toBe(false);
});
+ it("announces when severity rises from SEV 3–5 into SEV 2", () => {
+ expect(shouldAnnounceSeverityEscalation(5, 2)).toBe(true);
+ expect(shouldAnnounceSeverityEscalation(4, 2)).toBe(true);
+ });
+
+ it("does not announce moves between SEV 3–5", () => {
+ expect(shouldAnnounceSeverityEscalation(5, 3)).toBe(false);
+ expect(shouldAnnounceSeverityEscalation(4, 3)).toBe(false);
+ expect(shouldAnnounceSeverityEscalation(3, 5)).toBe(false);
+ });
+
+ it("does not announce SEV 1 to SEV 2 (already critical)", () => {
+ expect(shouldAnnounceSeverityEscalation(1, 2)).toBe(false);
+ });
+
it("does not announce SEV 2 to SEV 1 (already critical)", () => {
expect(shouldAnnounceSeverityEscalation(2, 1)).toBe(false);
});