import { describe, it, expect, vi, beforeEach } from "vitest"; import { get } from "svelte/store"; import { invoke } from "@tauri-apps/api/core"; import { setMockInvokeResult } from "../../../vitest.setup"; import { snippetsStore, type Snippet } from "./snippets"; describe("Snippet interface", () => { it("defines all required fields", () => { const snippet: Snippet = { id: "snippet-123", name: "Git Status", content: "git status", category: "Git", is_default: false, created_at: "2024-01-01T00:00:00Z", updated_at: "2024-01-01T00:00:00Z", }; expect(snippet.id).toBe("snippet-123"); expect(snippet.name).toBe("Git Status"); expect(snippet.content).toBe("git status"); expect(snippet.category).toBe("Git"); expect(snippet.is_default).toBe(false); expect(snippet.created_at).toBe("2024-01-01T00:00:00Z"); expect(snippet.updated_at).toBe("2024-01-01T00:00:00Z"); }); it("supports default snippets", () => { const defaultSnippet: Snippet = { id: "default-git-status", name: "Git Status", content: "git status --short", category: "Git", is_default: true, created_at: "2024-01-01T00:00:00Z", updated_at: "2024-01-01T00:00:00Z", }; expect(defaultSnippet.is_default).toBe(true); }); }); describe("snippetsStore", () => { beforeEach(() => { vi.clearAllMocks(); }); describe("store structure", () => { it("has all expected methods", () => { expect(typeof snippetsStore.loadSnippets).toBe("function"); expect(typeof snippetsStore.saveSnippet).toBe("function"); expect(typeof snippetsStore.createSnippet).toBe("function"); expect(typeof snippetsStore.updateSnippet).toBe("function"); expect(typeof snippetsStore.deleteSnippet).toBe("function"); expect(typeof snippetsStore.resetDefaults).toBe("function"); expect(typeof snippetsStore.setSelectedCategory).toBe("function"); }); it("has subscribable stores", () => { expect(typeof snippetsStore.snippets.subscribe).toBe("function"); expect(typeof snippetsStore.categories.subscribe).toBe("function"); expect(typeof snippetsStore.filteredSnippets.subscribe).toBe("function"); expect(typeof snippetsStore.isLoading.subscribe).toBe("function"); expect(typeof snippetsStore.selectedCategory.subscribe).toBe("function"); }); }); describe("loadSnippets", () => { it("loads snippets and categories from backend", async () => { const mockSnippets: Snippet[] = [ { id: "snippet-1", name: "Snippet 1", content: "content 1", category: "Git", is_default: false, created_at: "2024-01-01T00:00:00Z", updated_at: "2024-01-01T00:00:00Z", }, ]; const mockCategories = ["Git", "Shell", "Docker"]; setMockInvokeResult("list_snippets", mockSnippets); setMockInvokeResult("get_snippet_categories", mockCategories); await snippetsStore.loadSnippets(); expect(invoke).toHaveBeenCalledWith("list_snippets"); expect(invoke).toHaveBeenCalledWith("get_snippet_categories"); }); it("handles load errors gracefully", async () => { const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => {}); setMockInvokeResult("list_snippets", new Error("Failed to load")); await snippetsStore.loadSnippets(); expect(consoleSpy).toHaveBeenCalledWith("Failed to load snippets:", expect.any(Error)); consoleSpy.mockRestore(); }); }); describe("saveSnippet", () => { it("saves snippet and reloads list", async () => { const snippet: Snippet = { id: "snippet-123", name: "Test", content: "test content", category: "Test", is_default: false, created_at: "2024-01-01T00:00:00Z", updated_at: "2024-01-01T00:00:00Z", }; setMockInvokeResult("save_snippet", undefined); setMockInvokeResult("list_snippets", [snippet]); setMockInvokeResult("get_snippet_categories", ["Test"]); const result = await snippetsStore.saveSnippet(snippet); expect(result).toBe(true); expect(invoke).toHaveBeenCalledWith("save_snippet", { snippet }); }); it("handles save errors gracefully", async () => { const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => {}); setMockInvokeResult("save_snippet", new Error("Failed to save")); const snippet: Snippet = { id: "snippet-123", name: "Test", content: "test content", category: "Test", is_default: false, created_at: "2024-01-01T00:00:00Z", updated_at: "2024-01-01T00:00:00Z", }; const result = await snippetsStore.saveSnippet(snippet); expect(result).toBe(false); expect(consoleSpy).toHaveBeenCalledWith("Failed to save snippet:", expect.any(Error)); consoleSpy.mockRestore(); }); }); describe("createSnippet", () => { it("creates new snippet with generated ID and timestamps", async () => { setMockInvokeResult("save_snippet", undefined); setMockInvokeResult("list_snippets", []); setMockInvokeResult("get_snippet_categories", ["Shell"]); const result = await snippetsStore.createSnippet("My Snippet", "echo hello", "Shell"); expect(result).toBe(true); expect(invoke).toHaveBeenCalledWith( "save_snippet", expect.objectContaining({ snippet: expect.objectContaining({ name: "My Snippet", content: "echo hello", category: "Shell", is_default: false, }), }) ); }); }); describe("updateSnippet", () => { it("updates existing snippet preserving created_at", async () => { const existingSnippet: Snippet = { id: "snippet-123", name: "Old Name", content: "old content", category: "Old Category", is_default: false, created_at: "2024-01-01T00:00:00Z", updated_at: "2024-01-01T00:00:00Z", }; setMockInvokeResult("list_snippets", [existingSnippet]); setMockInvokeResult("save_snippet", undefined); setMockInvokeResult("get_snippet_categories", ["New Category"]); const result = await snippetsStore.updateSnippet( "snippet-123", "New Name", "new content", "New Category" ); expect(result).toBe(true); expect(invoke).toHaveBeenCalledWith( "save_snippet", expect.objectContaining({ snippet: expect.objectContaining({ id: "snippet-123", name: "New Name", content: "new content", category: "New Category", created_at: "2024-01-01T00:00:00Z", }), }) ); }); it("returns false for non-existent snippet", async () => { const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => {}); setMockInvokeResult("list_snippets", []); const result = await snippetsStore.updateSnippet( "non-existent", "Name", "content", "Category" ); expect(result).toBe(false); expect(consoleSpy).toHaveBeenCalledWith("Snippet not found for update"); consoleSpy.mockRestore(); }); }); describe("deleteSnippet", () => { it("deletes snippet by ID", async () => { setMockInvokeResult("delete_snippet", undefined); setMockInvokeResult("list_snippets", []); setMockInvokeResult("get_snippet_categories", []); const result = await snippetsStore.deleteSnippet("snippet-123"); expect(result).toBe(true); expect(invoke).toHaveBeenCalledWith("delete_snippet", { snippetId: "snippet-123" }); }); it("handles delete errors gracefully", async () => { const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => {}); setMockInvokeResult("delete_snippet", new Error("Cannot delete default snippet")); const result = await snippetsStore.deleteSnippet("default-1"); expect(result).toBe(false); expect(consoleSpy).toHaveBeenCalledWith("Failed to delete snippet:", expect.any(Error)); consoleSpy.mockRestore(); }); }); describe("resetDefaults", () => { it("resets default snippets", async () => { setMockInvokeResult("reset_default_snippets", undefined); setMockInvokeResult("list_snippets", []); setMockInvokeResult("get_snippet_categories", []); const result = await snippetsStore.resetDefaults(); expect(result).toBe(true); expect(invoke).toHaveBeenCalledWith("reset_default_snippets"); }); it("handles reset errors gracefully", async () => { const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => {}); setMockInvokeResult("reset_default_snippets", new Error("Reset failed")); const result = await snippetsStore.resetDefaults(); expect(result).toBe(false); expect(consoleSpy).toHaveBeenCalledWith( "Failed to reset default snippets:", expect.any(Error) ); consoleSpy.mockRestore(); }); }); describe("setSelectedCategory", () => { it("updates selected category", () => { snippetsStore.setSelectedCategory("Git"); expect(get(snippetsStore.selectedCategory)).toBe("Git"); }); it("can be cleared with null", () => { snippetsStore.setSelectedCategory("Git"); snippetsStore.setSelectedCategory(null); expect(get(snippetsStore.selectedCategory)).toBeNull(); }); }); describe("filteredSnippets", () => { it("returns all snippets when no category selected", async () => { const mockSnippets: Snippet[] = [ { id: "snippet-1", name: "Git Status", content: "git status", category: "Git", is_default: false, created_at: "2024-01-01T00:00:00Z", updated_at: "2024-01-01T00:00:00Z", }, { id: "snippet-2", name: "Docker PS", content: "docker ps", category: "Docker", is_default: false, created_at: "2024-01-01T00:00:00Z", updated_at: "2024-01-01T00:00:00Z", }, ]; setMockInvokeResult("list_snippets", mockSnippets); setMockInvokeResult("get_snippet_categories", ["Git", "Docker"]); await snippetsStore.loadSnippets(); snippetsStore.setSelectedCategory(null); const filtered = get(snippetsStore.filteredSnippets); expect(filtered).toHaveLength(2); }); it("filters snippets by selected category", async () => { const mockSnippets: Snippet[] = [ { id: "snippet-1", name: "Git Status", content: "git status", category: "Git", is_default: false, created_at: "2024-01-01T00:00:00Z", updated_at: "2024-01-01T00:00:00Z", }, { id: "snippet-2", name: "Docker PS", content: "docker ps", category: "Docker", is_default: false, created_at: "2024-01-01T00:00:00Z", updated_at: "2024-01-01T00:00:00Z", }, ]; setMockInvokeResult("list_snippets", mockSnippets); setMockInvokeResult("get_snippet_categories", ["Git", "Docker"]); await snippetsStore.loadSnippets(); snippetsStore.setSelectedCategory("Git"); const filtered = get(snippetsStore.filteredSnippets); expect(filtered).toHaveLength(1); expect(filtered[0].category).toBe("Git"); }); }); }); describe("snippet ID generation", () => { it("generates unique custom snippet IDs", () => { const generateId = () => `custom-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`; const id1 = generateId(); const id2 = generateId(); expect(id1).toMatch(/^custom-\d+-[a-z0-9]+$/); expect(id2).toMatch(/^custom-\d+-[a-z0-9]+$/); expect(id1).not.toBe(id2); }); }); describe("snippet validation", () => { it("requires non-empty name", () => { const snippet = { name: "" }; const isValid = snippet.name.trim().length > 0; expect(isValid).toBe(false); }); it("requires non-empty content", () => { const snippet = { content: " " }; const isValid = snippet.content.trim().length > 0; expect(isValid).toBe(false); }); it("requires non-empty category", () => { const snippet = { category: "Git" }; const isValid = snippet.category.trim().length > 0; expect(isValid).toBe(true); }); }); describe("snippet content types", () => { it("supports multiline content", () => { const snippet = { content: `git add . git commit -m "message" git push`, }; expect(snippet.content.includes("\n")).toBe(true); expect(snippet.content.split("\n")).toHaveLength(3); }); it("supports content with special characters", () => { const snippet = { content: "echo \"Hello, World!\" && echo 'Single quotes'", }; expect(snippet.content).toContain('"'); expect(snippet.content).toContain("'"); expect(snippet.content).toContain("&&"); }); it("supports content with variables", () => { const snippet = { content: "docker run -v $PWD:/app ${IMAGE_NAME}:${TAG}", }; expect(snippet.content).toContain("$PWD"); expect(snippet.content).toContain("${IMAGE_NAME}"); }); });