/** * Favorites service tests * * TRACES: UR-017 | DR-021 */ import { describe, it, expect, beforeEach, vi } from "vitest"; import { toggleFavorite } from "./favorites"; vi.mock("@tauri-apps/api/core", () => ({ invoke: vi.fn(async (command: string) => { if (command === "storage_toggle_favorite") { return undefined; } if (command === "storage_mark_synced") { return undefined; } return null; }), })); vi.mock("$lib/stores/auth", () => ({ auth: { getUserId: vi.fn(() => "user-123"), getRepository: vi.fn(() => ({ markFavorite: vi.fn(async () => undefined), unmarkFavorite: vi.fn(async () => undefined), })), }, })); describe("favorites service", () => { beforeEach(() => { vi.clearAllMocks(); }); describe("toggleFavorite", () => { it("should toggle favorite to true", async () => { const result = await toggleFavorite("item-123", false); expect(result).toBe(true); }); it("should toggle favorite to false", async () => { const result = await toggleFavorite("item-123", true); expect(result).toBe(false); }); it("should update local database", async () => { const { invoke } = await import("@tauri-apps/api/core"); const invokeSpy = vi.mocked(invoke); await toggleFavorite("item-123", false); const call = invokeSpy.mock.calls.find((c) => c[0] === "storage_toggle_favorite"); expect(call).toBeDefined(); expect(call![1]).toHaveProperty("itemId", "item-123"); expect(call![1]).toHaveProperty("isFavorite", true); }); it("should include userId in storage call", async () => { const { invoke } = await import("@tauri-apps/api/core"); const invokeSpy = vi.mocked(invoke); await toggleFavorite("item-123", false); const call = invokeSpy.mock.calls.find((c) => c[0] === "storage_toggle_favorite"); expect(call![1]).toHaveProperty("userId", "user-123"); }); it("should sync to server when marking as favorite", async () => { const { auth } = await import("$lib/stores/auth"); const authModule = vi.mocked(auth); const mockRepo = { markFavorite: vi.fn(async () => undefined), unmarkFavorite: vi.fn(async () => undefined), }; authModule.getRepository = vi.fn(() => mockRepo as any); await toggleFavorite("item-123", false); expect(mockRepo.markFavorite).toHaveBeenCalledWith("item-123"); }); it("should sync to server when unmarking as favorite", async () => { const { auth } = await import("$lib/stores/auth"); const authModule = vi.mocked(auth); const mockRepo = { markFavorite: vi.fn(async () => undefined), unmarkFavorite: vi.fn(async () => undefined), }; authModule.getRepository = vi.fn(() => mockRepo as any); await toggleFavorite("item-123", true); expect(mockRepo.unmarkFavorite).toHaveBeenCalledWith("item-123"); }); it("should mark as synced after successful server update", async () => { const { invoke } = await import("@tauri-apps/api/core"); const invokeSpy = vi.mocked(invoke); await toggleFavorite("item-123", false); const markSyncedCall = invokeSpy.mock.calls.find((c) => c[0] === "storage_mark_synced"); expect(markSyncedCall).toBeDefined(); expect(markSyncedCall![1]).toHaveProperty("itemId", "item-123"); }); it("should throw error if not authenticated", async () => { const { auth } = await import("$lib/stores/auth"); const authModule = vi.mocked(auth); authModule.getUserId = vi.fn(() => null); await expect(toggleFavorite("item-123", false)).rejects.toThrow("Not authenticated"); }); it("should handle server sync failure gracefully", async () => { const { auth } = await import("$lib/stores/auth"); const authModule = vi.mocked(auth); const mockRepo = { markFavorite: vi.fn(async () => { throw new Error("Server error"); }), unmarkFavorite: vi.fn(async () => undefined), }; authModule.getRepository = vi.fn(() => mockRepo as any); // Ensure getUserId returns a value for this test authModule.getUserId = vi.fn(() => "user-123"); // Should not throw, but return the new favorite state const result = await toggleFavorite("item-123", false); expect(result).toBe(true); }); it("should handle multiple toggles", async () => { const { auth } = await import("$lib/stores/auth"); const authModule = vi.mocked(auth); authModule.getUserId = vi.fn(() => "user-123"); let result = await toggleFavorite("item-123", false); expect(result).toBe(true); result = await toggleFavorite("item-123", true); expect(result).toBe(false); result = await toggleFavorite("item-123", false); expect(result).toBe(true); }); }); });