import { act, render, screen } from "@testing-library/react"; import { afterEach, beforeEach, expect, test, vi } from "vitest"; import { DatabiApp } from "./DatabiApp.jsx"; import { fetchFilterOptions, fetchStatisticsOverview } from "./api.js"; vi.mock("./api.js", () => ({ fetchFilterOptions: vi.fn(), fetchStatisticsOverview: vi.fn(), getCurrentAppCode: vi.fn(() => "lalu"), setCurrentAppCode: vi.fn((value) => String(value || "lalu").toLowerCase()) })); vi.mock("./charts/EChart.jsx", () => ({ EChart: () =>
})); beforeEach(() => { vi.useFakeTimers(); vi.setSystemTime(new Date("2026-06-06T08:00:00Z")); fetchFilterOptions.mockResolvedValue({ appOptions: [{ code: "lalu", label: "Lalu", value: "lalu" }], countryOptions: [{ countryCode: "", id: 0, label: "全部国家", regionIds: [], searchText: "全部国家 all", value: 0 }], regionOptions: [{ countryCodes: [], id: "all", label: "全部区域", value: "all" }] }); }); afterEach(() => { vi.useRealTimers(); vi.clearAllMocks(); }); test("keeps current data visible during scheduled refresh", async () => { const overview = { active_users: 10, paid_users: 2, recharge_usd_minor: 100, updated_at_ms: 1 }; fetchStatisticsOverview .mockResolvedValueOnce(overview) .mockResolvedValueOnce(overview) .mockImplementationOnce(() => new Promise(() => {})); render(); await flushEffects(); expect(screen.getAllByText("$1").length).toBeGreaterThan(0); expect(document.querySelector(".metric-card.is-loading")).toBeNull(); await act(async () => { vi.advanceTimersByTime(60_000); }); expect(fetchStatisticsOverview).toHaveBeenCalledTimes(3); expect(screen.getAllByText("$1").length).toBeGreaterThan(0); expect(document.querySelector(".metric-card.is-loading")).toBeNull(); }); async function flushEffects() { await act(async () => { for (let index = 0; index < 10; index += 1) { await Promise.resolve(); } }); }