Files
huskies/frontend/src/components/LozengeFlyContext.agentlozenge.test.tsx
T

150 lines
4.3 KiB
TypeScript
Raw Normal View History

2026-04-28 17:21:30 +00:00
import { render } from "@testing-library/react";
import * as React from "react";
import { describe, expect, it } from "vitest";
import type { PipelineState } from "../api/client";
import { LozengeFlyProvider } from "./LozengeFlyContext";
import { StagePanel } from "./StagePanel";
// ─── Helpers ──────────────────────────────────────────────────────────────────
function makePipeline(overrides: Partial<PipelineState> = {}): PipelineState {
return {
backlog: [],
current: [],
qa: [],
merge: [],
done: [],
2026-04-29 17:15:01 +00:00
deterministic_merges_in_flight: [],
2026-04-28 17:21:30 +00:00
...overrides,
};
}
function Wrapper({
pipeline,
children,
}: {
pipeline: PipelineState;
children: React.ReactNode;
}) {
return (
<LozengeFlyProvider pipeline={pipeline}>{children}</LozengeFlyProvider>
);
}
// ─── Agent lozenge fixed intrinsic width ──────────────────────────────────────
describe("AgentLozenge fixed intrinsic width", () => {
it("has align-self: flex-start so it never stretches inside a flex column", () => {
const items = [
{
story_id: "74_width_test",
name: "Width Test",
error: null,
merge_failure: null,
agent: { agent_name: "coder-1", model: "sonnet", status: "running" },
review_hold: null,
qa: null,
depends_on: null,
},
];
const pipeline = makePipeline({ current: items });
const { container } = render(
<Wrapper pipeline={pipeline}>
<StagePanel title="Current" items={items} />
</Wrapper>,
);
const lozenge = container.querySelector(
'[data-testid="slot-lozenge-74_width_test"]',
) as HTMLElement;
expect(lozenge).toBeInTheDocument();
expect(lozenge.style.alignSelf).toBe("flex-start");
});
});
// ─── Idle vs active visual distinction ────────────────────────────────────────
describe("AgentLozenge idle vs active appearance", () => {
it("running agent lozenge uses the green active color", () => {
const items = [
{
story_id: "74_running_color",
name: "Running",
error: null,
merge_failure: null,
agent: { agent_name: "coder-1", model: null, status: "running" },
review_hold: null,
qa: null,
depends_on: null,
},
];
const { container } = render(
<Wrapper pipeline={makePipeline({ current: items })}>
<StagePanel title="Current" items={items} />
</Wrapper>,
);
const lozenge = container.querySelector(
'[data-testid="slot-lozenge-74_running_color"]',
) as HTMLElement;
expect(lozenge).toBeInTheDocument();
// Green: rgb(63, 185, 80) = #3fb950
expect(lozenge.style.color).toBe("rgb(63, 185, 80)");
});
it("pending agent lozenge uses the yellow pending color", () => {
const items = [
{
story_id: "74_pending_color",
name: "Pending",
error: null,
merge_failure: null,
agent: { agent_name: "coder-1", model: null, status: "pending" },
review_hold: null,
qa: null,
depends_on: null,
},
];
const { container } = render(
<Wrapper pipeline={makePipeline({ current: items })}>
<StagePanel title="Current" items={items} />
</Wrapper>,
);
const lozenge = container.querySelector(
'[data-testid="slot-lozenge-74_pending_color"]',
) as HTMLElement;
expect(lozenge).toBeInTheDocument();
// Yellow: rgb(227, 179, 65) = #e3b341
expect(lozenge.style.color).toBe("rgb(227, 179, 65)");
});
it("running lozenge has a pulsing dot child element", () => {
const items = [
{
story_id: "74_pulse_dot",
name: "Pulse",
error: null,
merge_failure: null,
agent: { agent_name: "coder-1", model: null, status: "running" },
review_hold: null,
qa: null,
depends_on: null,
},
];
const { container } = render(
<Wrapper pipeline={makePipeline({ current: items })}>
<StagePanel title="Current" items={items} />
</Wrapper>,
);
const lozenge = container.querySelector(
'[data-testid="slot-lozenge-74_pulse_dot"]',
) as HTMLElement;
// The pulse dot is a child span with animation: pulse
const dot = lozenge.querySelector("span");
expect(dot).not.toBeNull();
expect(dot?.style.animation).toContain("pulse");
});
});