test(ui): matrix chat indicator rendering cases

This commit is contained in:
Peter Steinberger
2026-02-21 22:46:02 +00:00
parent 5fd1d2cadc
commit 7731f28a24

View File

@@ -50,118 +50,78 @@ function createProps(overrides: Partial<ChatProps> = {}): ChatProps {
}
describe("chat view", () => {
it("renders compacting indicator as a badge", () => {
const container = document.createElement("div");
render(
renderChat(
createProps({
it("renders/hides compaction and fallback indicators across recency states", () => {
const cases = [
{
name: "active compaction",
props: {
compactionStatus: {
active: true,
startedAt: Date.now(),
startedAt: 1_000,
completedAt: null,
},
}),
),
container,
);
const indicator = container.querySelector(".compaction-indicator--active");
expect(indicator).not.toBeNull();
expect(indicator?.textContent).toContain("Compacting context...");
});
it("renders completion indicator shortly after compaction", () => {
const container = document.createElement("div");
const nowSpy = vi.spyOn(Date, "now").mockReturnValue(1_000);
render(
renderChat(
createProps({
},
selector: ".compaction-indicator--active",
expectedText: "Compacting context...",
},
{
name: "recent compaction complete",
nowMs: 1_000,
props: {
compactionStatus: {
active: false,
startedAt: 900,
completedAt: 900,
},
}),
),
container,
);
const indicator = container.querySelector(".compaction-indicator--complete");
expect(indicator).not.toBeNull();
expect(indicator?.textContent).toContain("Context compacted");
nowSpy.mockRestore();
});
it("hides stale compaction completion indicator", () => {
const container = document.createElement("div");
const nowSpy = vi.spyOn(Date, "now").mockReturnValue(10_000);
render(
renderChat(
createProps({
},
selector: ".compaction-indicator--complete",
expectedText: "Context compacted",
},
{
name: "stale compaction hidden",
nowMs: 10_000,
props: {
compactionStatus: {
active: false,
startedAt: 0,
completedAt: 0,
},
}),
),
container,
);
expect(container.querySelector(".compaction-indicator")).toBeNull();
nowSpy.mockRestore();
});
it("renders fallback indicator shortly after fallback event", () => {
const container = document.createElement("div");
const nowSpy = vi.spyOn(Date, "now").mockReturnValue(1_000);
render(
renderChat(
createProps({
},
selector: ".compaction-indicator",
missing: true,
},
{
name: "recent fallback active",
nowMs: 1_000,
props: {
fallbackStatus: {
selected: "fireworks/minimax-m2p5",
active: "deepinfra/moonshotai/Kimi-K2.5",
attempts: ["fireworks/minimax-m2p5: rate limit"],
occurredAt: 900,
},
}),
),
container,
);
const indicator = container.querySelector(".compaction-indicator--fallback");
expect(indicator).not.toBeNull();
expect(indicator?.textContent).toContain("Fallback active: deepinfra/moonshotai/Kimi-K2.5");
nowSpy.mockRestore();
});
it("hides stale fallback indicator", () => {
const container = document.createElement("div");
const nowSpy = vi.spyOn(Date, "now").mockReturnValue(20_000);
render(
renderChat(
createProps({
},
selector: ".compaction-indicator--fallback",
expectedText: "Fallback active: deepinfra/moonshotai/Kimi-K2.5",
},
{
name: "stale fallback hidden",
nowMs: 20_000,
props: {
fallbackStatus: {
selected: "fireworks/minimax-m2p5",
active: "deepinfra/moonshotai/Kimi-K2.5",
attempts: [],
occurredAt: 0,
},
}),
),
container,
);
expect(container.querySelector(".compaction-indicator--fallback")).toBeNull();
nowSpy.mockRestore();
});
it("renders fallback-cleared indicator shortly after transition", () => {
const container = document.createElement("div");
const nowSpy = vi.spyOn(Date, "now").mockReturnValue(1_000);
render(
renderChat(
createProps({
},
selector: ".compaction-indicator--fallback",
missing: true,
},
{
name: "recent fallback cleared",
nowMs: 1_000,
props: {
fallbackStatus: {
phase: "cleared",
selected: "fireworks/minimax-m2p5",
@@ -170,15 +130,26 @@ describe("chat view", () => {
attempts: [],
occurredAt: 900,
},
}),
),
container,
);
},
selector: ".compaction-indicator--fallback-cleared",
expectedText: "Fallback cleared: fireworks/minimax-m2p5",
},
] as const;
const indicator = container.querySelector(".compaction-indicator--fallback-cleared");
expect(indicator).not.toBeNull();
expect(indicator?.textContent).toContain("Fallback cleared: fireworks/minimax-m2p5");
nowSpy.mockRestore();
for (const testCase of cases) {
const nowSpy =
testCase.nowMs === undefined ? null : vi.spyOn(Date, "now").mockReturnValue(testCase.nowMs);
const container = document.createElement("div");
render(renderChat(createProps(testCase.props)), container);
const indicator = container.querySelector(testCase.selector);
if (testCase.missing) {
expect(indicator, testCase.name).toBeNull();
} else {
expect(indicator, testCase.name).not.toBeNull();
expect(indicator?.textContent, testCase.name).toContain(testCase.expectedText);
}
nowSpy?.mockRestore();
}
});
it("shows a stop button when aborting is available", () => {