Files
fusion/packages/dashboard/app/test/mockApi.ts
gsxdsm 59803c243d FN-7123: use workflow settings for task models
Task model displays now resolve task-scoped workflow settings consistently with execution.

- Add a shared workflow settings overlay helper for stored workflow values and declaration defaults.
- Expose task effective settings through the dashboard API and consume them in TaskDetail model surfaces.
- Cover core overlay behavior, route output, and Workflow tab model rendering with regression tests.
- Document workflow model lane precedence and add a published package changeset.

Files changed:
 .changeset/fn-7123-workflow-tab-project-model.md   |   7 ++
 docs/settings-reference.md                         |  14 ++-
 .../__tests__/effective-settings-overlay.test.ts   |  70 ++++++++++++++
 packages/core/src/effective-settings-overlay.ts    |  27 ++++++
 packages/core/src/index.ts                         |   4 +
 packages/dashboard/app/api/legacy.ts               |   5 +
 .../dashboard/app/components/TaskDetailModal.tsx   |  13 ++-
 ...skDetailModal.models-progress-workflow.test.tsx |  46 +++++++++
 .../__tests__/TaskDetailModal.test-helpers.ts      |   1 +
 .../__tests__/WorkflowResultsTab.test.tsx          |  33 +++++++
 packages/dashboard/app/test/mockApi.ts             |   9 ++
 .../task-effective-settings-route.test.ts          | 107 +++++++++++++++++++++
 .../src/routes/register-task-workflow-routes.ts    |  21 ++++
 packages/engine/src/effective-settings.ts          |  25 ++---
 14 files changed, 355 insertions(+), 27 deletions(-)

Fusion-Task-Id: FN-7123

Fusion-Task-Lineage: 5fa9d338-c886-44aa-bdba-0d361b3602d5

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-06-27 12:20:42 -07:00

78 lines
3.0 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: Record<string, AnyFn> = {
fetchTasks: vi.fn(async () => []),
fetchSettings: vi.fn(async () => ({})),
fetchTaskEffectiveSettings: vi.fn().mockRejectedValue(new Error("fetchTaskEffectiveSettings: use fetchSettings mock")),
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 })),
};
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());
dashboardApiMocks.fetchTasks.mockResolvedValue([]);
dashboardApiMocks.fetchSettings.mockResolvedValue({});
dashboardApiMocks.fetchTaskEffectiveSettings.mockRejectedValue(new Error("fetchTaskEffectiveSettings: use fetchSettings mock"));
dashboardApiMocks.updateSettings.mockResolvedValue({});
dashboardApiMocks.fetchGlobalSettings.mockResolvedValue({});
dashboardApiMocks.fetchAuthStatus.mockResolvedValue({ providers: [] });
dashboardApiMocks.fetchModels.mockResolvedValue({ models: [], favoriteProviders: [], favoriteModels: [] });
dashboardApiMocks.fetchUnreadCount.mockResolvedValue({ unreadCount: 0 });
for (const fn of fallbackFns.values()) fn.mockReset();
}