Files
fusion/packages/dashboard/app/test/mockApi.ts
Fusion 04ff9d9403 feat(FN-3278): add direct-mode review tab to task detail modal
Merges FN-3278 review tab direct-mode (data, rendering, regression tests, typing fixes, and docs across Steps 2/3/6), FN-3750 mobile keyboard stabilization for mailbox and reply composer, FN-3751 fire-and-forget wake dispatch to prevent request hangs, and FN-3748 workspace aliases for @fusion/* pack

Fusion-Task-Id: FN-3278
2026-05-08 11:36:26 -07:00

69 lines
2.2 KiB
TypeScript

/**
* Canonical dashboard app API mock helper.
*
* Add new `app/api.ts` or `app/api/legacy.ts` exports here first before
* introducing ad-hoc per-test `vi.mock("../../api", …)` export lists.
*
* Behavior contract:
* - preserve real exports by default
* - apply canonical/common test mocks
* - allow per-suite overrides
* - auto-synthesize stable fallback fns for missing callable exports
*/
import { vi, type Mock } from "vitest";
type AnyFn = Mock;
type AnyModule = Record<string, unknown>;
const fallbackFns = new Map<string, AnyFn>();
function getFallback(name: string): AnyFn {
if (!fallbackFns.has(name)) {
fallbackFns.set(name, vi.fn(async () => undefined));
}
return fallbackFns.get(name)!;
}
export const dashboardApiMocks = {
fetchTasks: vi.fn(async () => []),
fetchSettings: vi.fn(async () => ({})),
updateSettings: vi.fn(async () => ({})),
fetchGlobalSettings: vi.fn(async () => ({})),
fetchAuthStatus: vi.fn(async () => ({ providers: [] })),
fetchModels: vi.fn(async () => ({ models: [], favoriteProviders: [], favoriteModels: [] })),
fetchTaskDetail: vi.fn(),
fetchTaskReview: vi.fn(),
fetchUnreadCount: vi.fn(async () => ({ unreadCount: 0 })),
} satisfies Record<string, AnyFn>;
export async function createDashboardApiMock(
importActual: () => Promise<AnyModule>,
overrides: Record<string, AnyFn> = {},
): Promise<AnyModule> {
const actual = await importActual();
const mocked: AnyModule = { ...actual, ...dashboardApiMocks, ...overrides };
return new Proxy(mocked, {
get(target, prop, receiver) {
if (typeof prop !== "string") return Reflect.get(target, prop, receiver);
if (Reflect.has(target, prop)) return Reflect.get(target, prop, receiver);
if (["then", "catch", "finally"].includes(prop)) {
return undefined;
}
const actualValue = (actual as AnyModule)[prop];
if (typeof actualValue === "function" || actualValue === undefined) {
const fn = getFallback(prop);
(target as AnyModule)[prop] = fn;
return fn;
}
return actualValue;
},
});
}
export function resetDashboardApiMockState(): void {
Object.values(dashboardApiMocks).forEach((fn) => fn.mockReset());
for (const fn of fallbackFns.values()) fn.mockReset();
}