Add DebugView component to show raw lore status data for visual verification that the data pipeline works end-to-end: - Frontend -> Tauri IPC -> Rust backend -> lore CLI -> parsed data New files: - src/components/DebugView.tsx - Debug component with health indicator - src/hooks/useLoreData.ts - TanStack Query hook for lore status - tests/components/DebugView.test.tsx - Component tests - tests/hooks/useLoreData.test.ts - Hook tests Modified: - src/App.tsx - Add QueryClientProvider wrapper - src/stores/nav-store.ts - Add 'debug' ViewId - src/components/AppShell.tsx - Add Debug nav tab and view routing - tests/components/AppShell.test.tsx - Update tests for new nav
98 lines
2.5 KiB
TypeScript
98 lines
2.5 KiB
TypeScript
import { describe, it, expect, beforeEach, vi } from "vitest";
|
|
import { renderHook, waitFor } from "@testing-library/react";
|
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
import { createElement } from "react";
|
|
import { useLoreData } from "@/hooks/useLoreData";
|
|
import { setMockResponse, resetMocks } from "../mocks/tauri-api";
|
|
|
|
function createWrapper() {
|
|
const queryClient = new QueryClient({
|
|
defaultOptions: {
|
|
queries: {
|
|
retry: false,
|
|
},
|
|
},
|
|
});
|
|
return function Wrapper({ children }: { children: React.ReactNode }) {
|
|
return createElement(QueryClientProvider, { client: queryClient }, children);
|
|
};
|
|
}
|
|
|
|
describe("useLoreData", () => {
|
|
beforeEach(() => {
|
|
resetMocks();
|
|
});
|
|
|
|
it("returns loading state initially", () => {
|
|
const { result } = renderHook(() => useLoreData(), {
|
|
wrapper: createWrapper(),
|
|
});
|
|
|
|
expect(result.current.isLoading).toBe(true);
|
|
expect(result.current.data).toBeUndefined();
|
|
});
|
|
|
|
it("returns lore status data on success", async () => {
|
|
const mockStatus = {
|
|
last_sync: "2026-02-26T12:00:00Z",
|
|
is_healthy: true,
|
|
message: "Lore is healthy",
|
|
summary: {
|
|
open_issues: 5,
|
|
authored_mrs: 2,
|
|
reviewing_mrs: 3,
|
|
},
|
|
};
|
|
|
|
setMockResponse("get_lore_status", mockStatus);
|
|
|
|
const { result } = renderHook(() => useLoreData(), {
|
|
wrapper: createWrapper(),
|
|
});
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.isLoading).toBe(false);
|
|
});
|
|
|
|
expect(result.current.data).toEqual(mockStatus);
|
|
expect(result.current.error).toBeNull();
|
|
});
|
|
|
|
it("returns error state when IPC fails", async () => {
|
|
setMockResponse("get_lore_status", Promise.reject(new Error("IPC failed")));
|
|
|
|
const { result } = renderHook(() => useLoreData(), {
|
|
wrapper: createWrapper(),
|
|
});
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.isLoading).toBe(false);
|
|
});
|
|
|
|
expect(result.current.error).toBeTruthy();
|
|
expect(result.current.data).toBeUndefined();
|
|
});
|
|
|
|
it("returns unhealthy status", async () => {
|
|
const mockStatus = {
|
|
last_sync: null,
|
|
is_healthy: false,
|
|
message: "lore not configured",
|
|
summary: null,
|
|
};
|
|
|
|
setMockResponse("get_lore_status", mockStatus);
|
|
|
|
const { result } = renderHook(() => useLoreData(), {
|
|
wrapper: createWrapper(),
|
|
});
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.isLoading).toBe(false);
|
|
});
|
|
|
|
expect(result.current.data?.is_healthy).toBe(false);
|
|
expect(result.current.data?.summary).toBeNull();
|
|
});
|
|
});
|