/* Copyright 2026 Marimo. All rights reserved. */ // @vitest-environment jsdom import { fireEvent, render, waitFor } from "@testing-library/react"; import { beforeEach, describe, expect, it, vi } from "vitest"; import { FilenameForm } from "../filename-form"; // Mock the hooks vi.mock("@/core/saving/filename", () => ({ useUpdateFilename: vi.fn(), })); vi.mock("@/core/saving/save-component", () => ({ useSaveNotebook: vi.fn(), })); // Mock FilenameInput to make testing easier vi.mock("@/components/editor/header/filename-input", () => ({ FilenameInput: ({ onNameChange, initialValue, }: { onNameChange: (value: string) => void; initialValue?: string | null; }) => ( onNameChange(e.target.value)} /> ), })); const mockUseUpdateFilename = vi.mocked( await import("@/core/saving/filename"), ).useUpdateFilename; const mockUseSaveNotebook = vi.mocked( await import("@/core/saving/save-component"), ).useSaveNotebook; describe("FilenameForm", () => { const mockUpdateFilename = vi.fn(); const mockSaveNotebook = vi.fn(); const mockSaveOrNameNotebook = vi.fn(); const mockSaveIfNotebookIsPersistent = vi.fn(); beforeEach(() => { vi.clearAllMocks(); mockUseUpdateFilename.mockReturnValue(mockUpdateFilename); mockUseSaveNotebook.mockReturnValue({ saveNotebook: mockSaveNotebook, saveOrNameNotebook: mockSaveOrNameNotebook, saveIfNotebookIsPersistent: mockSaveIfNotebookIsPersistent, }); }); it("should call saveNotebook when creating a new file from an unnamed notebook", async () => { // Setup: updateFilename resolves with the new filename mockUpdateFilename.mockResolvedValue("/path/to/new-file.py"); const { getByTestId } = render(); const input = getByTestId("filename-input"); // Simulate name change (user entering a filename) fireEvent.change(input, { target: { value: "new-file.py" } }); // Wait for the promise to resolve await waitFor(() => { expect(mockUpdateFilename).toHaveBeenCalledWith("new-file.py"); }); await waitFor(() => { expect(mockSaveNotebook).toHaveBeenCalledWith( "/path/to/new-file.py", true, ); }); }); it("should not call saveNotebook when renaming an existing file", async () => { // Setup: updateFilename resolves with the new filename mockUpdateFilename.mockResolvedValue("/path/to/renamed-file.py"); const { getByTestId } = render( , ); const input = getByTestId("filename-input"); // Simulate name change fireEvent.change(input, { target: { value: "renamed-file.py" } }); // Wait for the promise to resolve await waitFor(() => { expect(mockUpdateFilename).toHaveBeenCalledWith("renamed-file.py"); }); // saveNotebook should NOT be called because the file was already named expect(mockSaveNotebook).not.toHaveBeenCalled(); }); it("should not call saveNotebook when updateFilename returns null", async () => { // Setup: updateFilename resolves with null (e.g., user cancelled or error) mockUpdateFilename.mockResolvedValue(null); const { getByTestId } = render(); const input = getByTestId("filename-input"); // Simulate name change fireEvent.change(input, { target: { value: "new-file.py" } }); // Wait for the promise to resolve await waitFor(() => { expect(mockUpdateFilename).toHaveBeenCalled(); }); // saveNotebook should NOT be called because updateFilename returned null expect(mockSaveNotebook).not.toHaveBeenCalled(); }); });