/* Copyright 2026 Marimo. All rights reserved. */ import { act, renderHook } from "@testing-library/react"; import { createStore, Provider } from "jotai"; import type { ReactNode } from "react"; import { describe, expect, it, vi } from "vitest"; import { userConfigAtom } from "@/core/config/config"; import { defaultUserConfig } from "@/core/config/config-schema"; import { requestClientAtom } from "@/core/network/requests"; import type { EditRequests, RunRequests } from "@/core/network/types"; import { AiModelId } from "../ids/ids"; import { useAIConfigActions } from "../config"; describe("useAIConfigActions", () => { it("persists a model change without overwriting newer AI config", async () => { const store = createStore(); const saveUserConfig = vi.fn().mockResolvedValue(null); store.set(userConfigAtom, defaultUserConfig()); store.set(requestClientAtom, { saveUserConfig, } as unknown as EditRequests & RunRequests); const wrapper = ({ children }: { children: ReactNode }) => ( {children} ); const { result } = renderHook(() => useAIConfigActions(), { wrapper }); store.set(userConfigAtom, (config) => ({ ...config, ai: { ...config.ai, mode: "agent", }, })); await act(async () => { await result.current.saveModelChange( AiModelId.parse("openai/gpt-4o").id, "chat", ); }); expect(saveUserConfig).toHaveBeenCalledWith({ config: { ai: { models: { chat_model: "openai/gpt-4o" } } }, }); expect(store.get(userConfigAtom).ai).toMatchObject({ mode: "agent", models: { chat_model: "openai/gpt-4o" }, }); }); it("preserves concurrent AI changes when saves resolve out of order", async () => { const store = createStore(); const resolvers: Array<() => void> = []; const saveUserConfig = vi.fn( () => new Promise((resolve) => { resolvers.push(() => resolve(null)); }), ); store.set(userConfigAtom, defaultUserConfig()); store.set(requestClientAtom, { saveUserConfig, } as unknown as EditRequests & RunRequests); const wrapper = ({ children }: { children: ReactNode }) => ( {children} ); const { result } = renderHook(() => useAIConfigActions(), { wrapper }); const modelChange = result.current.saveModelChange( AiModelId.parse("openai/gpt-4o").id, "chat", ); const modeChange = result.current.saveModeChange("agent"); expect(saveUserConfig).toHaveBeenNthCalledWith(1, { config: { ai: { models: { chat_model: "openai/gpt-4o" } } }, }); expect(saveUserConfig).toHaveBeenNthCalledWith(2, { config: { ai: { mode: "agent" } }, }); await act(async () => { resolvers[1](); await modeChange; resolvers[0](); await modelChange; }); expect(store.get(userConfigAtom).ai).toMatchObject({ mode: "agent", models: { chat_model: "openai/gpt-4o" }, }); }); });