feat(FN-2092): merge fusion/fn-2092
This commit is contained in:
@@ -41,6 +41,7 @@ vi.mock("../../api", async (importOriginal) => {
|
||||
fetchGitRemotes: vi.fn(() => Promise.resolve([])),
|
||||
fetchAgents: vi.fn(() => Promise.resolve([])),
|
||||
fetchTaskDetail: vi.fn((id: string) => Promise.resolve({ id, title: `Task ${id}` })),
|
||||
fetchUnreadCount: vi.fn(() => Promise.resolve({ unreadCount: 0 })),
|
||||
fetchScripts: vi.fn(() => Promise.resolve({ build: "npm run build", test: "pnpm test" })),
|
||||
runScript: vi.fn(() => Promise.resolve({ sessionId: "sess-script-1", command: "echo hello" })),
|
||||
killPtyTerminalSession: vi.fn(() => Promise.resolve({ killed: true })),
|
||||
@@ -220,7 +221,7 @@ vi.mock("../../hooks/useNodes", () => ({
|
||||
}));
|
||||
|
||||
import { App } from "../../App";
|
||||
import { fetchAuthStatus, fetchSettings, fetchGlobalSettings, fetchTaskDetail, updateSettings, runScript, fetchScripts, fetchModels } from "../../api";
|
||||
import { fetchAuthStatus, fetchSettings, fetchGlobalSettings, fetchTaskDetail, fetchUnreadCount, updateSettings, runScript, fetchScripts, fetchModels } from "../../api";
|
||||
import * as apiNodeModule from "../../hooks/useRemoteNodeData";
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -276,6 +277,30 @@ beforeEach(() => {
|
||||
mockGetStepData.mockReturnValue(null);
|
||||
});
|
||||
|
||||
describe("App mailbox unread count", () => {
|
||||
it("logs a warning when unread count fetch fails and keeps the zero-count fallback", async () => {
|
||||
const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
|
||||
const unreadFetchError = new Error("Mailbox unavailable");
|
||||
(fetchUnreadCount as ReturnType<typeof vi.fn>).mockRejectedValueOnce(unreadFetchError);
|
||||
|
||||
render(<App />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(fetchUnreadCount).toHaveBeenCalledWith("proj_123");
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(warnSpy).toHaveBeenCalledWith(
|
||||
"[App] Failed to fetch mailbox unread count:",
|
||||
unreadFetchError,
|
||||
);
|
||||
});
|
||||
|
||||
expect(screen.getByRole("status", { name: "Loading Fusion dashboard" })).toBeInTheDocument();
|
||||
warnSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
|
||||
describe("App deep link handling", () => {
|
||||
const originalLocation = window.location;
|
||||
const originalReplaceState = window.history.replaceState;
|
||||
|
||||
@@ -3,6 +3,7 @@ import { render, screen, fireEvent, waitFor, act } from "@testing-library/react"
|
||||
import { MissionManager } from "../MissionManager";
|
||||
|
||||
const mockFetchAiSession = vi.fn();
|
||||
const mockFetchAiSessions = vi.fn();
|
||||
const mockCancelMissionInterview = vi.fn();
|
||||
const mockConnectMissionInterviewStream = vi.fn();
|
||||
const mockPreviewEnrichedDescription = vi.fn();
|
||||
@@ -15,7 +16,7 @@ vi.mock("../../api", async () => {
|
||||
return {
|
||||
...actual,
|
||||
fetchAiSession: (...args: any[]) => mockFetchAiSession(...args),
|
||||
fetchAiSessions: () => Promise.resolve([]),
|
||||
fetchAiSessions: (...args: any[]) => mockFetchAiSessions(...args),
|
||||
cancelMissionInterview: (...args: any[]) => mockCancelMissionInterview(...args),
|
||||
connectMissionInterviewStream: (...args: any[]) => mockConnectMissionInterviewStream(...args),
|
||||
previewEnrichedDescription: (...args: any[]) => mockPreviewEnrichedDescription(...args),
|
||||
@@ -647,9 +648,11 @@ describe("MissionManager", () => {
|
||||
originalFetch = globalThis.fetch;
|
||||
originalEventSource = globalThis.EventSource;
|
||||
mockFetchAiSession.mockReset();
|
||||
mockFetchAiSessions.mockReset();
|
||||
mockCancelMissionInterview.mockReset();
|
||||
mockConnectMissionInterviewStream.mockReset();
|
||||
mockFetchAiSession.mockResolvedValue(null);
|
||||
mockFetchAiSessions.mockResolvedValue([]);
|
||||
mockCancelMissionInterview.mockResolvedValue(undefined);
|
||||
mockConnectMissionInterviewStream.mockReturnValue({
|
||||
close: vi.fn(),
|
||||
@@ -1577,6 +1580,54 @@ describe("MissionManager", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("logs a warning when pending interview session fetch fails", async () => {
|
||||
const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
|
||||
const pendingFetchError = new Error("Pending sessions failed");
|
||||
mockFetchAiSessions.mockRejectedValueOnce(pendingFetchError);
|
||||
globalThis.fetch = createFetchMock();
|
||||
|
||||
render(<MissionManager isOpen={true} isInline={true} onClose={vi.fn()} addToast={vi.fn()} />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(warnSpy).toHaveBeenCalledWith(
|
||||
"[MissionManager] Failed to fetch pending interview sessions:",
|
||||
pendingFetchError,
|
||||
);
|
||||
});
|
||||
|
||||
expect(screen.getByText("Missions")).toBeInTheDocument();
|
||||
warnSpy.mockRestore();
|
||||
});
|
||||
|
||||
it("logs a warning when milestone/slice resume session fetch fails", async () => {
|
||||
const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
|
||||
const resumeFetchError = new Error("Resume session failed");
|
||||
const onResumeFetchError = vi.fn();
|
||||
mockFetchAiSession.mockRejectedValueOnce(resumeFetchError);
|
||||
globalThis.fetch = createFetchMock();
|
||||
|
||||
render(
|
||||
<MissionManager
|
||||
isOpen={true}
|
||||
isInline={true}
|
||||
onClose={vi.fn()}
|
||||
addToast={vi.fn()}
|
||||
milestoneSliceResumeSessionId="sess-resume-1"
|
||||
onMilestoneSliceResumeFetchError={onResumeFetchError}
|
||||
/>,
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(warnSpy).toHaveBeenCalledWith(
|
||||
"[MissionManager] Failed to fetch session for milestone/slice resume:",
|
||||
resumeFetchError,
|
||||
);
|
||||
});
|
||||
|
||||
expect(onResumeFetchError).toHaveBeenCalledTimes(1);
|
||||
warnSpy.mockRestore();
|
||||
});
|
||||
|
||||
it("shows milestone hierarchy in detail view", async () => {
|
||||
globalThis.fetch = createDetailFetchMock();
|
||||
render(<MissionManager isOpen={true} onClose={vi.fn()} addToast={vi.fn()} />);
|
||||
|
||||
Reference in New Issue
Block a user