Add comprehensive test coverage for services and utilities
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,159 @@
|
||||
/**
|
||||
* 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);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user