Files
fusion/packages/dashboard/app/components/__tests__/NewTaskModal.shared-cache.test.tsx
gsxdsm 338e7286c0 FN-6395: align viewport hook mocks in dashboard tests
Update dashboard test doubles so mobile viewport helpers match the hook module API.

- Add getViewportMode and isMobileViewport exports to affected useViewportMode mocks.
- Keep mocked mobile detection tied to each test's configurable viewport mode.
- Normalize inline viewport mocks across dashboard component test suites.

Files changed:
 .../components/__tests__/AgentsView.orgchart.test.tsx   |  6 +++++-
 .../app/components/__tests__/AgentsView.test.tsx        |  2 ++
 .../app/components/__tests__/ChatView.rooms.test.tsx    |  1 +
 .../app/components/__tests__/GitManagerModal.test.tsx   |  2 ++
 .../app/components/__tests__/MailboxView.test.tsx       | 13 +++++++++----
 .../__tests__/MilestoneSliceInterviewModal.test.tsx     |  2 ++
 .../__tests__/MissionManager.swipe-back.test.tsx        |  2 ++
 .../__tests__/NewTaskModal.shared-cache.test.tsx        | 17 ++++++++++++++---
 .../app/components/__tests__/NewTaskModal.test.tsx      |  2 ++
 .../__tests__/PlanningModeModal.favorites.test.tsx      |  2 ++
 .../__tests__/PlanningModeModal.questions.test.tsx      |  2 ++
 .../__tests__/PlanningModeModal.swipe-back.test.tsx     |  2 ++
 .../PlanningModeModal.ui-interactions.test.tsx          |  4 ++++
 .../components/__tests__/QuickChatFAB.autosize.test.tsx | 13 +++++++++----
 .../__tests__/QuickChatFAB.shared-cache.test.tsx        | 11 +++++++++--
 .../app/components/__tests__/QuickChatFAB.test.tsx      | 11 +++++++++--
 .../__tests__/SettingsModal.testMode.test.tsx           |  6 +++++-
 .../components/__tests__/SubtaskBreakdownModal.test.tsx |  2 ++
 .../app/components/__tests__/TodoModal.test.tsx         |  2 ++
 .../components/__tests__/navigation-history.test.tsx    |  3 ++-
 20 files changed, 87 insertions(+), 18 deletions(-)

Fusion-Task-Id: FN-6395
Fusion-Task-Lineage: d830938b-4d60-4e17-852d-a2d311b6d71c
2026-06-13 16:30:28 -07:00

118 lines
4.0 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from "vitest";
import { fireEvent, render, screen } from "@testing-library/react";
import { NewTaskModal } from "../NewTaskModal";
import { useAgentsMapCache } from "../../hooks/useAgentsMapCache";
import { writeCache, SWR_CACHE_KEYS } from "../../utils/swrCache";
const mockFetchAgents = vi.fn();
vi.mock("../../api", async (importOriginal) => {
const actual = await importOriginal<typeof import("../../api")>();
return {
...actual,
fetchAgents: (...args: unknown[]) => mockFetchAgents(...args),
uploadAttachment: vi.fn().mockResolvedValue({ attachment: null }),
};
});
vi.mock("../../hooks/useSetupReadiness", () => ({ useSetupReadiness: vi.fn(() => ({ hasAiProvider: true, hasGithub: true, loading: false })) }));
vi.mock("../../hooks/useConfirm", () => ({ useConfirm: vi.fn(() => ({ confirm: vi.fn().mockResolvedValue(true) })) }));
vi.mock("../../hooks/useMobileKeyboard", () => ({ useMobileKeyboard: vi.fn(() => ({ keyboardOverlap: 0, viewportHeight: null, viewportOffsetTop: 0, keyboardOpen: false })) }));
vi.mock("../../hooks/useMobileScrollLock", () => ({
useMobileScrollLock: vi.fn(),
useMobileKeyboardViewportLock: vi.fn(),
useMobileViewportRestoreReset: vi.fn(),
}));
vi.mock("../../hooks/useNodes", () => ({ useNodes: vi.fn(() => ({ nodes: [] })) }));
vi.mock("../../hooks/useViewportMode", () => {
const useViewportMode = vi.fn(() => "desktop");
return {
MOBILE_MEDIA_QUERY: "(max-width: 768px), (max-height: 480px)",
getViewportMode: () => useViewportMode(),
isMobileViewport: () => useViewportMode() === "mobile",
useViewportMode,
};
});
function deferred<T>() {
let resolve!: (value: T) => void;
const promise = new Promise<T>((res) => {
resolve = res;
});
return { promise, resolve };
}
describe("NewTaskModal shared cache", () => {
beforeEach(() => {
vi.clearAllMocks();
localStorage.clear();
mockFetchAgents.mockResolvedValue([]);
});
const baseProps = {
isOpen: true,
projectId: "p1",
tasks: [],
onCreateTask: vi.fn(),
addToast: vi.fn(),
onClose: vi.fn(),
};
it("shows cached agents without cold fetch", () => {
writeCache(`${SWR_CACHE_KEYS.CHAT_AGENTS_MAP_PREFIX}p1`, [
{ id: "agent-1", name: "Agent One", role: "executor", state: "active" },
{ id: "agent-2", name: "Agent Two", role: "reviewer", state: "active" },
], { maxBytes: 500_000 });
render(<NewTaskModal {...baseProps} />);
fireEvent.click(screen.getByTestId("new-task-agent-button"));
expect(screen.getByText("Agent One")).toBeInTheDocument();
expect(screen.getByText("Agent Two")).toBeInTheDocument();
});
it("reuses warm cache across remounts", () => {
writeCache(`${SWR_CACHE_KEYS.CHAT_AGENTS_MAP_PREFIX}p1`, [
{ id: "agent-1", name: "Agent One", role: "executor", state: "active" },
], { maxBytes: 500_000 });
const first = render(<NewTaskModal {...baseProps} />);
first.unmount();
render(<NewTaskModal {...baseProps} />);
expect(mockFetchAgents.mock.calls.length).toBeLessThanOrEqual(1);
});
it("dedups agent fetch with another useAgentsMapCache consumer", () => {
const request = deferred<Array<{ id: string; name: string; role: string; state: string }>>();
mockFetchAgents.mockReturnValue(request.promise);
function AgentsConsumer() {
useAgentsMapCache("p1");
return null;
}
render(
<>
<NewTaskModal {...baseProps} />
<AgentsConsumer />
</>,
);
expect(mockFetchAgents).toHaveBeenCalledTimes(1);
request.resolve([]);
});
it("opens picker synchronously on cache hit", () => {
writeCache(`${SWR_CACHE_KEYS.CHAT_AGENTS_MAP_PREFIX}p1`, [
{ id: "agent-1", name: "Agent One", role: "executor", state: "active" },
], { maxBytes: 500_000 });
render(<NewTaskModal {...baseProps} />);
fireEvent.click(screen.getByTestId("new-task-agent-button"));
expect(screen.getByText("Select agent")).toBeInTheDocument();
expect(screen.queryByText("Loading agents...")).toBeNull();
});
});