/** * @file ReportSettings.test.tsx * @description Settings → Reports: a new report is saved with the browser's * timezone offset, Run now runs it, and History lists the runs with download * links built from the report and run ids. * @author Nguyễn Ngọc Trí Vĩ */ import { render, screen, waitFor } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { beforeEach, describe, expect, it, vi } from "vitest"; import i18n from "i18next"; const { reports } = vi.hoisted(() => ({ reports: { list: vi.fn(), create: vi.fn(), update: vi.fn(), remove: vi.fn(), run: vi.fn(), runs: vi.fn(), fileUrl: (id: number, runId: number, f: string) => `/api/reports/${id}/runs/${runId}/${f}`, }, })); vi.mock("../../../lib/api", () => ({ api: { reports } })); import { ReportSettings } from "../ReportSettings"; const DEF = { id: 3, name: "Weekly summary", window_days: 7, frequency: "weekly" as const, hour: 8, weekday: 1, tz_offset: 0, formats: ["html" as const, "json" as const], enabled: true, created_at: "2026-10-01T00:00:00Z", last_slot: null, last_run: null, }; const RUN = { id: 9, report_id: 3, created_at: "2026-10-05T01:00:00Z", trigger: "manual" as const, status: "ok" as const, window_from: "2026-09-28", window_to: "2026-10-04", files: ["html", "json"], error: null, }; beforeEach(() => { i18n.changeLanguage("en"); vi.clearAllMocks(); }); describe("ReportSettings", () => { it("creates a report with the browser's timezone offset", async () => { const user = userEvent.setup(); reports.list.mockResolvedValueOnce({ reports: [] }).mockResolvedValue({ reports: [DEF] }); reports.create.mockResolvedValue({ report: DEF }); render(); await user.click(await screen.findByRole("button", { name: /New report/ })); await user.click(screen.getByRole("checkbox", { name: "JSON" })); await user.click(screen.getByRole("button", { name: "Save" })); await waitFor(() => expect(reports.create).toHaveBeenCalledWith({ name: "Weekly summary", window_days: 7, frequency: "weekly", hour: 8, weekday: 1, tz_offset: new Date().getTimezoneOffset(), formats: ["html", "json"], enabled: true, }) ); expect(await screen.findByText(/last 7 days · HTML, JSON/)).toBeInTheDocument(); }); it("runs a report now and lists its runs with download links", async () => { const user = userEvent.setup(); reports.list.mockResolvedValue({ reports: [DEF] }); reports.run.mockResolvedValue({ run: RUN }); reports.runs.mockResolvedValue({ runs: [RUN] }); render(); await user.click(await screen.findByRole("button", { name: "Run now" })); expect(reports.run).toHaveBeenCalledWith(3); await user.click(screen.getByRole("button", { name: "History" })); const link = await screen.findByRole("link", { name: /HTML/ }); expect(link).toHaveAttribute("href", "/api/reports/3/runs/9/html"); expect(screen.getByText(/2026-09-28 → 2026-10-04/)).toBeInTheDocument(); }); });