99 lines
3.0 KiB
TypeScript
99 lines
3.0 KiB
TypeScript
import { cleanup, render, screen } from "@testing-library/react";
|
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
import { TooltipProvider } from "@kandev/ui/tooltip";
|
|
import type { SentryIssueWatch } from "@/lib/types/sentry";
|
|
import { SentryIssueWatchTable } from "./sentry-issue-watch-table";
|
|
|
|
function watch(over: Partial<SentryIssueWatch>): SentryIssueWatch {
|
|
return {
|
|
id: "w1",
|
|
workspaceId: "ws-1",
|
|
sentryInstanceId: "inst-1",
|
|
workflowId: "wf",
|
|
workflowStepId: "step",
|
|
repositoryId: "",
|
|
baseBranch: "",
|
|
filter: { orgSlug: "acme", projectSlugs: ["web"] },
|
|
agentProfileId: "ap",
|
|
executorProfileId: "",
|
|
prompt: "",
|
|
enabled: true,
|
|
pollIntervalSeconds: 300,
|
|
lastPolledAt: null,
|
|
lastError: "",
|
|
lastErrorAt: null,
|
|
createdAt: "",
|
|
updatedAt: "",
|
|
...over,
|
|
} as unknown as SentryIssueWatch;
|
|
}
|
|
|
|
const noop = vi.fn();
|
|
|
|
function resolveName(id: string): string {
|
|
if (id === "inst-1") return "Production";
|
|
if (id === "") return "—";
|
|
return "(unavailable)";
|
|
}
|
|
|
|
function renderTable(watches: SentryIssueWatch[]) {
|
|
return render(
|
|
<TooltipProvider>
|
|
<SentryIssueWatchTable
|
|
watches={watches}
|
|
dirtyIds={new Set(watches.slice(0, 1).map(({ id }) => id))}
|
|
instanceName={resolveName}
|
|
onEdit={noop}
|
|
onDelete={noop}
|
|
onTrigger={noop}
|
|
onReset={noop}
|
|
onToggleEnabled={noop}
|
|
/>
|
|
</TooltipProvider>,
|
|
);
|
|
}
|
|
|
|
afterEach(() => {
|
|
cleanup();
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
describe("SentryIssueWatchTable", () => {
|
|
it("shows an Instance column, not a Workspace column (integration is workspace-scoped)", () => {
|
|
renderTable([watch({ id: "w1" })]);
|
|
expect(screen.getByText("Instance")).toBeTruthy();
|
|
expect(screen.queryByText("Workspace")).toBeNull();
|
|
});
|
|
|
|
it("renders each watch's bound instance name via the resolver", () => {
|
|
renderTable([
|
|
watch({ id: "w1", sentryInstanceId: "inst-1" }),
|
|
watch({ id: "w2", sentryInstanceId: "inst-gone" }),
|
|
watch({ id: "w3", sentryInstanceId: "" }),
|
|
]);
|
|
const cells = screen.getAllByTestId("watch-instance").map((c) => c.textContent);
|
|
expect(cells).toEqual(["Production", "(unavailable)", "—"]);
|
|
});
|
|
|
|
it("marks the changed watcher row and enable control dirty", () => {
|
|
renderTable([watch({ id: "w1" }), watch({ id: "w2" })]);
|
|
|
|
expect(screen.getByTestId("sentry-watch-row-w1").getAttribute("data-settings-dirty")).toBe(
|
|
"true",
|
|
);
|
|
expect(screen.getByTestId("sentry-watch-enabled-w1").getAttribute("data-settings-dirty")).toBe(
|
|
"true",
|
|
);
|
|
expect(screen.getByTestId("sentry-watch-row-w2").getAttribute("data-settings-dirty")).toBe(
|
|
"false",
|
|
);
|
|
});
|
|
|
|
it("renders a comma-joined project list in the filter summary for a multi-project watch", () => {
|
|
renderTable([
|
|
watch({ id: "w1", filter: { orgSlug: "acme", projectSlugs: ["frontend", "backend"] } }),
|
|
]);
|
|
expect(screen.getByText("org:acme · project:frontend,backend")).toBeTruthy();
|
|
});
|
|
});
|