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"> { const base: Record = { _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"> { const base: Record = { _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>) 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[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>) 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[0] const result = await backlogOverviewHandler(ctx, { tenantId: TENANT_ID, viewerId: VIEWER_ID, range: "7d", }) expect(result.rangeDays).toBe(7) expect(result.statusCounts).toMatchObject({ 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 }, ]) ) }) })