sistema-de-chamados/tests/reports.sla-backlog.test.ts

199 lines
5.8 KiB
TypeScript

import { afterAll, beforeAll, describe, expect, it, vi } from "bun:test"
vi.mock("../convex/rbac", () => ({
requireStaff: vi.fn(),
}))
import type { Doc, Id } from "../convex/_generated/dataModel"
import { backlogOverviewHandler, slaOverviewHandler } from "../convex/reports"
import { requireStaff } from "../convex/rbac"
import { createReportsCtx } from "./utils/report-test-helpers"
const TENANT_ID = "tenant-1"
const VIEWER_ID = "user-staff" as Id<"users">
function buildTicket(overrides: Partial<Doc<"tickets">>): Doc<"tickets"> {
const base: Record<string, unknown> = {
_id: "ticket_base" as Id<"tickets">,
tenantId: TENANT_ID,
reference: 50000,
subject: "Chamado",
summary: null,
status: "PENDING",
priority: "MEDIUM",
channel: "EMAIL",
queueId: undefined,
requesterId: "user_req" as Id<"users">,
requesterSnapshot: { name: "Alice", email: "alice@example.com", avatarUrl: undefined, teams: [] },
assigneeId: "user_agent" as Id<"users">,
assigneeSnapshot: { name: "Bob", email: "bob@example.com", avatarUrl: undefined, teams: [] },
companyId: undefined,
companySnapshot: undefined,
machineId: undefined,
machineSnapshot: undefined,
working: false,
dueAt: undefined,
firstResponseAt: undefined,
resolvedAt: undefined,
closedAt: undefined,
updatedAt: Date.now(),
createdAt: Date.now(),
tags: [],
customFields: [],
totalWorkedMs: 0,
internalWorkedMs: 0,
externalWorkedMs: 0,
activeSessionId: undefined,
}
return { ...(base as Doc<"tickets">), ...overrides }
}
function buildQueue(overrides: Partial<Doc<"queues">>): Doc<"queues"> {
const base: Record<string, unknown> = {
_id: "queue_base" as Id<"queues">,
tenantId: TENANT_ID,
name: "Suporte",
slug: "suporte",
createdAt: Date.now(),
updatedAt: Date.now(),
}
return { ...(base as Doc<"queues">), ...overrides }
}
describe("convex.reports.slaOverview", () => {
const requireStaffMock = vi.mocked(requireStaff)
const FIXED_NOW = Date.UTC(2024, 4, 8, 12, 0, 0)
beforeAll(() => {
vi.useFakeTimers()
vi.setSystemTime(FIXED_NOW)
})
afterAll(() => {
vi.useRealTimers()
})
it("summarizes totals, averages and queue breakdown", async () => {
requireStaffMock.mockResolvedValue({
role: "ADMIN",
user: { companyId: undefined },
} as unknown as Awaited<ReturnType<typeof requireStaff>>)
const queue = buildQueue({
_id: "queue_1" as Id<"queues">,
name: "Suporte Nível 1",
})
const tickets = [
buildTicket({
_id: "ticket_open" as Id<"tickets">,
status: "PENDING",
queueId: queue._id,
createdAt: Date.UTC(2024, 4, 7, 9, 0, 0),
dueAt: Date.UTC(2024, 4, 7, 11, 0, 0),
}),
buildTicket({
_id: "ticket_resolved" as Id<"tickets">,
status: "RESOLVED",
queueId: queue._id,
createdAt: Date.UTC(2024, 4, 6, 8, 0, 0),
firstResponseAt: Date.UTC(2024, 4, 6, 8, 30, 0),
resolvedAt: Date.UTC(2024, 4, 6, 10, 0, 0),
}),
]
const ctx = createReportsCtx({ tickets, queues: [queue] }) as Parameters<typeof slaOverviewHandler>[0]
const result = await slaOverviewHandler(ctx, {
tenantId: TENANT_ID,
viewerId: VIEWER_ID,
range: "7d",
})
expect(result.rangeDays).toBe(7)
expect(result.totals).toEqual({ total: 2, open: 1, resolved: 1, overdue: 1 })
expect(result.response).toEqual({ averageFirstResponseMinutes: 30, responsesRegistered: 1 })
expect(result.resolution).toEqual({ averageResolutionMinutes: 120, resolvedCount: 1 })
expect(result.queueBreakdown).toEqual([{ id: queue._id, name: queue.name, open: 1 }])
})
})
describe("convex.reports.backlogOverview", () => {
const requireStaffMock = vi.mocked(requireStaff)
const FIXED_NOW = Date.UTC(2024, 6, 1, 12, 0, 0)
beforeAll(() => {
vi.useFakeTimers()
vi.setSystemTime(FIXED_NOW)
})
afterAll(() => {
vi.useRealTimers()
})
it("aggregates status, priority and queue counts for open tickets", async () => {
requireStaffMock.mockResolvedValue({
role: "ADMIN",
user: { companyId: undefined },
} as unknown as Awaited<ReturnType<typeof requireStaff>>)
const queueA = buildQueue({ _id: "queue_a" as Id<"queues">, name: "Atendimento" })
const queueB = buildQueue({ _id: "queue_b" as Id<"queues">, name: "Infraestrutura" })
const tickets = [
buildTicket({
_id: "ticket_pending" as Id<"tickets">,
status: "PENDING",
priority: "HIGH",
queueId: queueA._id,
createdAt: Date.UTC(2024, 5, 28, 10, 0, 0),
}),
buildTicket({
_id: "ticket_paused" as Id<"tickets">,
status: "PAUSED",
priority: "MEDIUM",
queueId: queueB._id,
createdAt: Date.UTC(2024, 5, 29, 15, 0, 0),
}),
buildTicket({
_id: "ticket_resolved" as Id<"tickets">,
status: "RESOLVED",
priority: "URGENT",
queueId: undefined,
createdAt: Date.UTC(2024, 5, 27, 9, 0, 0),
}),
]
const ctx = createReportsCtx({
tickets,
createdRangeTickets: tickets,
queues: [queueA, queueB],
}) as Parameters<typeof backlogOverviewHandler>[0]
const result = await backlogOverviewHandler(ctx, {
tenantId: TENANT_ID,
viewerId: VIEWER_ID,
range: "7d",
})
expect(result.rangeDays).toBe(7)
expect(result.statusCounts).toEqual({
PENDING: 1,
PAUSED: 1,
RESOLVED: 1,
})
expect(result.priorityCounts).toEqual({
HIGH: 1,
MEDIUM: 1,
URGENT: 1,
})
expect(result.totalOpen).toBe(2)
expect(result.queueCounts).toHaveLength(2)
expect(result.queueCounts).toEqual(
expect.arrayContaining([
{ id: "queue_a", name: queueA.name, total: 1 },
{ id: "queue_b", name: queueB.name, total: 1 },
])
)
})
})