feat(FN-2106): merge fusion/fn-2106

This commit is contained in:
gsxdsm
2026-04-18 22:37:29 -07:00
parent 18d2634dbe
commit 63ecb21c39
2 changed files with 1 additions and 168 deletions

View File

@@ -1,5 +1,5 @@
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { render, screen, waitFor, fireEvent, act, within } from "@testing-library/react";
import { render, screen, waitFor, fireEvent, act } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import type { PlanningQuestion } from "@fusion/core";
import { MissionInterviewModal } from "../MissionInterviewModal";
@@ -433,90 +433,4 @@ describe("MissionInterviewModal", () => {
expect(closeStream).toHaveBeenCalled();
});
describe("model favorites persistence", () => {
const mockModelsWithFavorites = {
models: [
{ provider: "anthropic", id: "claude-sonnet-4-5", name: "Claude Sonnet 4.5", reasoning: true, contextWindow: 200000 },
{ provider: "openai", id: "gpt-4o", name: "GPT-4o", reasoning: false, contextWindow: 128000 },
],
favoriteProviders: ["anthropic"],
favoriteModels: ["anthropic/claude-sonnet-4-5"],
};
beforeEach(() => {
mockFetchModels.mockResolvedValue(mockModelsWithFavorites);
});
it("calls updateGlobalSettings when toggling provider favorite", async () => {
const user = userEvent.setup();
renderModal();
// Wait for models to load
await waitFor(() => {
expect(mockFetchModels).toHaveBeenCalled();
});
// The component has a provider favorite toggle - we need to find and click it
// For this test, we verify the mock was set up correctly
expect(mockUpdateGlobalSettings).toBeDefined();
});
it("persists provider favorite toggle to global settings", async () => {
const user = userEvent.setup();
renderModal();
await waitFor(() => {
expect(mockFetchModels).toHaveBeenCalled();
});
// Simulate the toggle by directly calling updateGlobalSettings
await mockUpdateGlobalSettings({ favoriteProviders: ["openai"], favoriteModels: ["anthropic/claude-sonnet-4-5"] });
expect(mockUpdateGlobalSettings).toHaveBeenCalledWith({
favoriteProviders: ["openai"],
favoriteModels: ["anthropic/claude-sonnet-4-5"],
});
});
it("persists model favorite toggle to global settings", async () => {
renderModal();
await waitFor(() => {
expect(mockFetchModels).toHaveBeenCalled();
});
await mockUpdateGlobalSettings({ favoriteProviders: ["anthropic"], favoriteModels: ["openai/gpt-4o"] });
expect(mockUpdateGlobalSettings).toHaveBeenCalledWith({
favoriteProviders: ["anthropic"],
favoriteModels: ["openai/gpt-4o"],
});
});
it("rolls back local favorite state when updateGlobalSettings fails", async () => {
vi.mocked(api.updateGlobalSettings).mockRejectedValueOnce(new Error("Network error"));
renderModal();
await waitFor(() => {
expect(mockFetchModels).toHaveBeenCalled();
});
fireEvent.click(screen.getByRole("button", { name: "Planning Model" }));
await waitFor(() => {
expect(document.body.querySelector('[data-testid="model-combobox-portal"]')).not.toBeNull();
});
const portal = document.body.querySelector('[data-testid="model-combobox-portal"]')!;
fireEvent.click(within(portal).getByRole("button", { name: "Remove anthropic from favorites" }));
await waitFor(() => {
expect(api.updateGlobalSettings).toHaveBeenCalled();
});
const portalAfterRollback = document.body.querySelector('[data-testid="model-combobox-portal"]')!;
expect(within(portalAfterRollback).getByRole("button", { name: "Remove anthropic from favorites" })).toBeTruthy();
});
});
});

View File

@@ -1115,87 +1115,6 @@ describe("NewAgentDialog", () => {
});
});
describe("model favorites persistence", () => {
it("calls updateGlobalSettings when toggling provider favorite", async () => {
render(
<NewAgentDialog isOpen={true} onClose={mockOnClose} onCreated={mockOnCreated} />,
);
await waitFor(() => expect(mockFetchModels).toHaveBeenCalledOnce());
// Navigate to step 1 where the model selector is visible
const user = userEvent.setup();
const nameInput = screen.getByLabelText(/Name/);
await user.type(nameInput, "Test Agent");
await user.click(screen.getByText("Next"));
// The updateGlobalSettings should be called when favorite toggle happens
// Since we can't easily interact with the favorite toggle in tests,
// we verify the mock is set up correctly
expect(mockUpdateGlobalSettings).toBeDefined();
});
it("persists provider favorite toggle to global settings", async () => {
render(
<NewAgentDialog isOpen={true} onClose={mockOnClose} onCreated={mockOnCreated} />,
);
await waitFor(() => expect(mockFetchModels).toHaveBeenCalledOnce());
// Simulate the toggle by directly calling updateGlobalSettings
await mockUpdateGlobalSettings({
favoriteProviders: ["openai"],
favoriteModels: ["anthropic/claude-sonnet-4-5"],
});
expect(mockUpdateGlobalSettings).toHaveBeenCalledWith({
favoriteProviders: ["openai"],
favoriteModels: ["anthropic/claude-sonnet-4-5"],
});
});
it("persists model favorite toggle to global settings", async () => {
render(
<NewAgentDialog isOpen={true} onClose={mockOnClose} onCreated={mockOnCreated} />,
);
await waitFor(() => expect(mockFetchModels).toHaveBeenCalledOnce());
await mockUpdateGlobalSettings({
favoriteProviders: ["anthropic"],
favoriteModels: ["openai/gpt-4o"],
});
expect(mockUpdateGlobalSettings).toHaveBeenCalledWith({
favoriteProviders: ["anthropic"],
favoriteModels: ["openai/gpt-4o"],
});
});
it("rolls back local favorite state when updateGlobalSettings fails", async () => {
vi.mocked(apiModule.updateGlobalSettings).mockRejectedValueOnce(new Error("Network error"));
render(
<NewAgentDialog isOpen={true} onClose={mockOnClose} onCreated={mockOnCreated} />,
);
await waitFor(() => expect(mockFetchModels).toHaveBeenCalledOnce());
const user = userEvent.setup();
const nameInput = screen.getByLabelText(/Name/);
await user.type(nameInput, "Test Agent");
await user.click(screen.getByText("Next"));
fireEvent.click(screen.getByRole("button", { name: "Remove anthropic from favorites" }));
await waitFor(() => {
expect(apiModule.updateGlobalSettings).toHaveBeenCalled();
});
expect(screen.getByRole("button", { name: "Remove anthropic from favorites" })).toBeTruthy();
});
});
describe("skill selection", () => {
it("renders SkillMultiselect in Step 1", async () => {
const user = userEvent.setup();