evOo-local/packages/ui-web/src/bot-avatar-moment.test.tsx
cynarAI 55df4a6439
feat(avatar): let Oos react to what their bots do (#141)
A bot's Oo now cheers for a moment when its run finishes, the stage Oo
follows the pointer and squishes when tapped, and chat headers show the
speaking bot's own Oo instead of the generic mascot. Small avatars in
lists only animate while working or waiting so long lists stay calm.


Claude-Session: https://claude.ai/code/session_01EKuME5CgL1ddGGN7LGvtBj

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-05 01:51:37 +02:00

43 lines
1.3 KiB
TypeScript

// @vitest-environment jsdom
import { act } from "react";
import { createRoot, type Root } from "react-dom/client";
import { afterEach, beforeEach, expect, it, vi } from "vitest";
import { BotAvatar } from "./bot-avatar.js";
let container: HTMLDivElement;
let root: Root;
beforeEach(() => {
(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true;
vi.useFakeTimers();
container = document.createElement("div");
document.body.append(container);
root = createRoot(container);
});
afterEach(() => {
act(() => root.unmount());
container.remove();
vi.useRealTimers();
});
function moment() {
return container.querySelector("svg[data-oo-moment]")?.getAttribute("data-oo-moment");
}
it("celebrates when a run finishes, then settles", () => {
act(() => root.render(<BotAvatar color="#8B5CF6" status="running" size={72} />));
expect(moment()).toBe("working");
act(() => root.render(<BotAvatar color="#8B5CF6" status="completed" size={72} />));
expect(moment()).toBe("success");
act(() => vi.advanceTimersByTime(3000));
expect(moment()).toBe("idle");
});
it("does not celebrate a failed run", () => {
act(() => root.render(<BotAvatar color="#8B5CF6" status="running" size={72} />));
act(() => root.render(<BotAvatar color="#8B5CF6" status="failed" size={72} />));
expect(moment()).toBe("concerned");
});