mirror of
https://github.com/DeusData/codebase-memory-mcp.git
synced 2026-11-12 09:47:20 +08:00
Distilled from #789 (safe features only). Adds backend dead-code classification (status + in_calls in the layout JSON), a GET /api/repo-info endpoint for GitHub deep-links, and the frontend dead-code filters, node code preview, and deep-links. The render-cap revert was dropped (kept 2000 for DEFAULT_MAX_NODES/HARD_MAX_NODES and GRAPH_RENDER_NODE_LIMIT); the sidebar regex-search refactor was omitted. Security fixes over the original: repo-info strips credentials from any returned remote_url; the legitimate https blob-URL construction is allow-listed so the static gate passes; libgit2 is not re-initialized/shutdown per request (reuses the process-wide init from cbm_alloc_init); deep-link path segments are URL-encoded. Co-authored-by: Andy Zehady <azehady@ciroos.ai> Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
65 lines
2.1 KiB
TypeScript
65 lines
2.1 KiB
TypeScript
/* @vitest-environment jsdom */
|
|
import "@testing-library/jest-dom/vitest";
|
|
import { fireEvent, render, screen } from "@testing-library/react";
|
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
import { GraphTab } from "./GraphTab";
|
|
import type { GraphData } from "../lib/types";
|
|
|
|
/* GraphScene renders a WebGL <Canvas> which jsdom can't run — stub it out. */
|
|
vi.mock("./GraphScene", () => ({
|
|
GraphScene: () => null,
|
|
computeCameraTarget: () => null,
|
|
}));
|
|
|
|
const SAMPLE: GraphData = {
|
|
nodes: [
|
|
{
|
|
id: 1, x: 0, y: 0, z: 0, label: "Function", name: "orphan",
|
|
file_path: "src/orphan.ts", size: 1, color: "#fff", status: "dead", in_calls: 0,
|
|
},
|
|
{
|
|
id: 2, x: 1, y: 0, z: 0, label: "Function", name: "used",
|
|
file_path: "src/used.ts", size: 1, color: "#fff", status: "normal", in_calls: 3,
|
|
},
|
|
],
|
|
edges: [{ source: 2, target: 1, type: "CALLS" }],
|
|
total_nodes: 2,
|
|
};
|
|
|
|
function mockLayoutFetch(data: GraphData) {
|
|
const fetchMock = vi.fn(async (input: RequestInfo | URL) => {
|
|
const url = String(input);
|
|
if (url.startsWith("/api/layout")) {
|
|
return new Response(JSON.stringify(data), {
|
|
status: 200,
|
|
headers: { "Content-Type": "application/json" },
|
|
});
|
|
}
|
|
return new Response("{}", { status: 200 });
|
|
});
|
|
vi.stubGlobal("fetch", fetchMock);
|
|
return fetchMock;
|
|
}
|
|
|
|
describe("GraphTab dead-code filters", () => {
|
|
afterEach(() => {
|
|
vi.unstubAllGlobals();
|
|
});
|
|
|
|
it("shows the dead count and filters to only dead code on toggle", async () => {
|
|
mockLayoutFetch(SAMPLE);
|
|
render(<GraphTab project="demo" />);
|
|
|
|
/* Panel loaded; the dead-code section reports one dead node. */
|
|
expect(await screen.findByText("Filters")).toBeInTheDocument();
|
|
expect(screen.getByText("1 dead")).toBeInTheDocument();
|
|
|
|
/* Both nodes visible initially — no "filtered from" notice. */
|
|
expect(screen.queryByText(/filtered from/)).not.toBeInTheDocument();
|
|
|
|
/* Toggling "Show only dead code" hides the non-dead node. */
|
|
fireEvent.click(screen.getByRole("button", { name: /Show only dead code/ }));
|
|
expect(await screen.findByText(/filtered from 2/)).toBeInTheDocument();
|
|
});
|
|
});
|