diff --git a/packages/dashboard/app/hooks/__tests__/useTasks-hydration-freshness.test.ts b/packages/dashboard/app/hooks/__tests__/useTasks-hydration-freshness.test.ts index 64929c2c2e..f9fbceb094 100644 --- a/packages/dashboard/app/hooks/__tests__/useTasks-hydration-freshness.test.ts +++ b/packages/dashboard/app/hooks/__tests__/useTasks-hydration-freshness.test.ts @@ -1,4 +1,7 @@ /* +FNXC:MobileTabDiscard 2026-08-02-03:10: +The quarantine rescue fixes its off-by-one root cause with one fake system clock installed before every fixture. Exact epoch assertions remain required: tolerance, retries, or real-clock reads would conceal a hydration-freshness regression. + FNXC:MobileTabDiscard 2026-07-26-14:26: Regression coverage for the freshness half of the mobile tab-discard restore. @@ -14,7 +17,7 @@ render, not just after a fetch. Asserted against real localStorage and the real a mocked cache is what let the missing `savedAt` plumbing hide. */ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; -import { act, renderHook, waitFor } from "@testing-library/react"; +import { act, renderHook } from "@testing-library/react"; import type { Task } from "@fusion/core"; import { useTasks } from "../useTasks"; import * as api from "../../api"; @@ -102,7 +105,16 @@ function seedSnapshot(tasks: Task[], ageMs: number): number { return savedAt; } +/** Flush the resolved fetch promise without advancing the controlled system clock. */ +async function flushAsyncUpdates(): Promise { + await act(async () => { + await Promise.resolve(); + }); +} + beforeEach(() => { + vi.useFakeTimers(); + vi.setSystemTime(new Date("2026-07-30T12:00:00.000Z")); sseHarness.subscriptions.length = 0; MockEventSource.instances = []; (globalThis as unknown as { EventSource: unknown }).EventSource = MockEventSource; @@ -186,9 +198,8 @@ describe("useTasks hydration freshness (dataAsOfMs)", () => { const { result } = renderHook(() => useTasks({ projectId: PROJECT_ID })); expect(result.current.lastFetchTimeMs).toBe(savedAt); - await waitFor(() => { - expect(result.current.tasks.map((task) => task.id)).toEqual(["FN-NEW"]); - }); + await flushAsyncUpdates(); + expect(result.current.tasks.map((task) => task.id)).toEqual(["FN-NEW"]); expect(result.current.lastFetchTimeMs).toBeGreaterThan(savedAt); }); @@ -220,9 +231,8 @@ describe("useTasks hydration freshness (dataAsOfMs)", () => { rerender({ projectId: otherProjectId }); - await waitFor(() => { - expect(result.current.tasks.map((task) => task.id)).toEqual(["FN-B"]); - }); + await flushAsyncUpdates(); + expect(result.current.tasks.map((task) => task.id)).toEqual(["FN-B"]); expect(result.current.lastFetchTimeMs).toBe(otherSavedAt); }); }); @@ -294,13 +304,11 @@ describe("useTasks freshness clock vs single-row live updates", () => { mockFetchTasks.mockResolvedValue([createInProgressTask("FN-CONFIRMED", Date.now())]); const { result } = renderHook(() => useTasks({ projectId: PROJECT_ID })); - await waitFor(() => { - expect(result.current.tasks.map((task) => task.id)).toEqual(["FN-CONFIRMED"]); - }); + await flushAsyncUpdates(); + expect(result.current.tasks.map((task) => task.id)).toEqual(["FN-CONFIRMED"]); const confirmedAt = result.current.lastFetchTimeMs; expect(confirmedAt).toBeDefined(); - vi.useFakeTimers({ shouldAdvanceTime: true }); vi.setSystemTime(Date.now() + 5 * 60_000); emitSse("task:updated", createInProgressTask("FN-CONFIRMED", Date.now())); diff --git a/packages/dashboard/vitest.config.ts b/packages/dashboard/vitest.config.ts index 914db5be66..5887af5dd6 100644 --- a/packages/dashboard/vitest.config.ts +++ b/packages/dashboard/vitest.config.ts @@ -344,14 +344,6 @@ HMR channel, watcher, and plugin container deterministically. Browser viewport a required responsive acceptance lane, so the test must not remain excluded from dashboard-api. */ const quarantinedDashboardTests: string[] = [ - /* - FNXC:DashboardTestQuarantine 2026-07-30-12:30: - Wall-clock off-by-one-millisecond: the freshness clock case asserts exact epoch equality against a - value derived from a second real-clock read. 1 failure in 3 identical runs, with the change under - test (PR #2731) living in a different hook and provably unrelated — stashing it did not stop the - variance. Quarantined on sight rather than appeased; the fix is fake timers, not a tolerance. - */ - "app/hooks/__tests__/useTasks-hydration-freshness.test.ts", /* FNXC:DashboardTestQuarantine 2026-08-01-05:17: FN-8647 observed the real Pi ModelRuntime Kimi K3 catalog test timing out in 2/6 diff --git a/scripts/lib/test-quarantine.json b/scripts/lib/test-quarantine.json index d200bb7386..41eaf9c293 100644 --- a/scripts/lib/test-quarantine.json +++ b/scripts/lib/test-quarantine.json @@ -1,11 +1,6 @@ { "$comment": "Flaky-test quarantine ledger (deletion ratchet \u2014 see AGENTS.md 'Flaky tests: quarantine on sight' and docs/testing.md 'Quarantine ledger and the deletion ratchet'). A test observed failing without a corresponding real bug is quarantined ON SIGHT: add an entry here AND a matching one-line `exclude` entry in that package's vitest config, in the same commit. Every entry needs a non-empty `reason` (link the failing run) and a `quarantinedAt` date \u2014 the entry expires 14 days later, at which point the test file is DELETED unless someone rescues it with evidence it catches real regressions plus a root-cause fix (never appeasement). There is deliberately no loader module and no automation around this file: it is a dated record, the vitest config is the enforcement.", "entries": [ - { - "file": "packages/dashboard/app/hooks/__tests__/useTasks-hydration-freshness.test.ts", - "reason": "Wall-clock off-by-one-millisecond in 'task:created does not advance the clock while an unconfirmed hydrated snapshot is on screen' \u2014 asserts an exact epoch equality against a value derived from a second real-clock read. Observed 1 failure in 3 identical local runs (AssertionError: expected 1785409894615 to be 1785409894614) while working PR #2731, whose change is in a different hook (useTaskDiffStats) and cannot affect it; the same file passed 11/11 with that change stashed and then failed again with it restored, so the variance is the clock, not the diff. Quarantined on sight per AGENTS.md rather than appeased \u2014 the root-cause fix is fake timers or a tolerance-free monotonic source, not a widened assertion.", - "quarantinedAt": "2026-07-30" - }, { "file": "packages/dashboard/src/__tests__/register-model-routes-kimi-k3-supplemental.test.ts", "reason": "Real Pi SDK ModelRuntime catalog construction timed out at the 15s test budget in 2/6 sampled loaded CI runs; failing run https://github.com/Runfusion/Fusion/actions/runs/30664201149 and issue https://github.com/Runfusion/Fusion/issues/3245. FN-8647 landed a reusable shared-construction seam without widening timeouts. FN-8669 must obtain an owner budget decision and re-measure CI before the 14-day deletion deadline.",