160 lines
4.9 KiB
TypeScript
160 lines
4.9 KiB
TypeScript
/**
|
|
* 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);
|
|
});
|
|
});
|
|
});
|