feat(FN-3087): add immediate wake controls for agent inbox and message API,
This merge ships five distinct features: experimental-flag gating for research tools in the CLI extension and core settings, immediate wake controls for the agent inbox and message API enabling on-demand heartbeat triggers, separation of plugin lifecycle from setup probe state in the dashboard, grap Fusion-Task-Id: FN-3087
This commit is contained in:
@@ -100,6 +100,7 @@ describe("DependencyGraph highlighting", () => {
|
||||
expect(edgeCB?.className.baseVal || edgeCB?.className).toContain("graph-edge--highlighted");
|
||||
|
||||
fireEvent.click(screen.getByTestId("task-C"));
|
||||
expect(onOpenDetail).toHaveBeenCalledTimes(1);
|
||||
expect(onOpenDetail).toHaveBeenCalledWith(expect.objectContaining({ id: "C" }));
|
||||
});
|
||||
|
||||
|
||||
@@ -111,10 +111,11 @@ describe("DependencyGraph", () => {
|
||||
expect(fitToGraph).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("clicking a card triggers onOpenDetail", () => {
|
||||
it("clicking a card triggers onOpenDetail exactly once", () => {
|
||||
const onOpenDetail = vi.fn();
|
||||
render(<DependencyGraph tasks={[createTask("A", "in-progress")]} onOpenDetail={onOpenDetail} />);
|
||||
fireEvent.click(screen.getByTestId("task-A"));
|
||||
expect(onOpenDetail).toHaveBeenCalledTimes(1);
|
||||
expect(onOpenDetail).toHaveBeenCalledWith(expect.objectContaining({ id: "A" }));
|
||||
});
|
||||
|
||||
|
||||
@@ -220,13 +220,26 @@ describe("GraphTaskNode", () => {
|
||||
expect(screen.getByTestId("graph-task-node-FN-TEST").hasAttribute("data-current-step")).toBe(false);
|
||||
});
|
||||
|
||||
it("clicking card opens task detail", () => {
|
||||
it("clicking card opens task detail exactly once", () => {
|
||||
const props = createProps(createTask());
|
||||
const { container } = render(<GraphTaskNode {...props} />);
|
||||
|
||||
const card = container.querySelector(".card");
|
||||
expect(card).toBeTruthy();
|
||||
fireEvent.click(card!);
|
||||
expect(props.onOpenDetail).toHaveBeenCalledTimes(1);
|
||||
expect(props.onOpenDetail).toHaveBeenCalledWith(expect.objectContaining({ id: "FN-TEST" }));
|
||||
});
|
||||
|
||||
it("clicking active indicator surface opens task detail", () => {
|
||||
const props = createProps(createTask({ column: "in-progress", status: "executing" }));
|
||||
const { container } = render(<GraphTaskNode {...props} />);
|
||||
|
||||
const indicator = container.querySelector(".graph-task-active-indicator");
|
||||
expect(indicator).toBeTruthy();
|
||||
fireEvent.click(indicator!);
|
||||
|
||||
expect(props.onOpenDetail).toHaveBeenCalledTimes(1);
|
||||
expect(props.onOpenDetail).toHaveBeenCalledWith(expect.objectContaining({ id: "FN-TEST" }));
|
||||
});
|
||||
|
||||
|
||||
@@ -1,9 +1,20 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { createElement } from "react";
|
||||
import { cleanup, fireEvent, render, screen } from "@testing-library/react";
|
||||
import { describe, expect, it, vi, afterEach } from "vitest";
|
||||
import { definePlugin } from "@fusion/plugin-sdk";
|
||||
import { validatePluginManifest } from "@fusion/core";
|
||||
import plugin from "../index";
|
||||
import plugin, { DependencyGraphDashboardView } from "../index";
|
||||
import { getPluginViewId } from "../../../../packages/dashboard/app/plugins/pluginViewRegistry";
|
||||
|
||||
vi.mock("@fusion/dashboard/app/components/TaskCard", () => ({
|
||||
TaskCard: ({ task, onOpenDetail }: { task: { id: string }; onOpenDetail: (task: { id: string }) => void }) =>
|
||||
createElement("button", { "data-testid": `task-${task.id}`, onClick: () => onOpenDetail(task) }, task.id),
|
||||
}));
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
describe("dependency graph plugin host integration contract", () => {
|
||||
it("declares dashboard view manifest shape", () => {
|
||||
expect(plugin.manifest.id).toBe("fusion-plugin-dependency-graph");
|
||||
@@ -43,4 +54,20 @@ describe("dependency graph plugin host integration contract", () => {
|
||||
|
||||
expect(getPluginViewId(plugin.manifest.id, view.viewId)).toBe("plugin:fusion-plugin-dependency-graph:graph");
|
||||
});
|
||||
|
||||
it("uses host openTaskDetail context when rendered through dashboard view entrypoint", () => {
|
||||
const openTaskDetail = vi.fn();
|
||||
render(
|
||||
createElement(DependencyGraphDashboardView, {
|
||||
context: {
|
||||
tasks: [{ id: "FN-HOST", description: "FN-HOST", column: "todo", dependencies: [], steps: [], currentStep: 0, log: [] }],
|
||||
openTaskDetail,
|
||||
} as never,
|
||||
}),
|
||||
);
|
||||
|
||||
fireEvent.click(screen.getByTestId("task-FN-HOST"));
|
||||
expect(openTaskDetail).toHaveBeenCalledTimes(1);
|
||||
expect(openTaskDetail).toHaveBeenCalledWith(expect.objectContaining({ id: "FN-HOST" }));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -65,6 +65,7 @@ describe("dependency graph interactions", () => {
|
||||
render(<DependencyGraph tasks={[createTask("A", "in-progress")]} onOpenDetail={onOpenDetail} />);
|
||||
|
||||
fireEvent.click(screen.getByTestId("task-A"));
|
||||
expect(onOpenDetail).toHaveBeenCalledTimes(1);
|
||||
expect(onOpenDetail).toHaveBeenCalledWith(expect.objectContaining({ id: "A" }));
|
||||
expect(screen.getAllByText(/Executing/).length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user