import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { TrayPopover } from "@/components/TrayPopover";
import { makeFocusItem } from "../helpers/fixtures";
describe("TrayPopover", () => {
describe("with focus item", () => {
it("shows 'THE ONE THING' header", () => {
const item = makeFocusItem({ title: "Review MR !847" });
render();
expect(screen.getByText("THE ONE THING")).toBeInTheDocument();
});
it("shows focus item title", () => {
const item = makeFocusItem({ title: "Fix auth bug" });
render();
expect(screen.getByText("Fix auth bug")).toBeInTheDocument();
});
it("shows project path", () => {
const item = makeFocusItem({ project: "platform/core" });
render();
expect(screen.getByText(/platform\/core/)).toBeInTheDocument();
});
it("shows type badge", () => {
const item = makeFocusItem({ type: "mr_review" });
render();
expect(screen.getByText(/review/i)).toBeInTheDocument();
});
it("shows Start button", () => {
const item = makeFocusItem();
render();
expect(screen.getByRole("button", { name: /start/i })).toBeInTheDocument();
});
it("shows Defer button", () => {
const item = makeFocusItem();
render();
expect(screen.getByRole("button", { name: /defer/i })).toBeInTheDocument();
});
it("shows Skip button", () => {
const item = makeFocusItem();
render();
expect(screen.getByRole("button", { name: /skip/i })).toBeInTheDocument();
});
});
describe("empty state", () => {
it("shows empty message when no focus item", () => {
render();
expect(screen.getByText(/nothing focused/i)).toBeInTheDocument();
});
it("does not show action buttons when empty", () => {
render();
expect(screen.queryByRole("button", { name: /start/i })).not.toBeInTheDocument();
expect(screen.queryByRole("button", { name: /defer/i })).not.toBeInTheDocument();
expect(screen.queryByRole("button", { name: /skip/i })).not.toBeInTheDocument();
});
});
describe("counts", () => {
it("shows queue count", () => {
render();
expect(screen.getByText("Queue: 4")).toBeInTheDocument();
});
it("shows inbox count", () => {
render();
expect(screen.getByText("Inbox: 3")).toBeInTheDocument();
});
it("shows both counts", () => {
render();
expect(screen.getByText("Queue: 5")).toBeInTheDocument();
expect(screen.getByText("Inbox: 2")).toBeInTheDocument();
});
});
describe("full window link", () => {
it("shows keyboard shortcut hint", () => {
render();
// Should show some reference to opening full window
expect(screen.getByText(/full window/i)).toBeInTheDocument();
});
});
describe("actions", () => {
it("calls onStart when Start clicked", async () => {
const user = userEvent.setup();
const onStart = vi.fn();
const item = makeFocusItem();
render(
);
await user.click(screen.getByRole("button", { name: /start/i }));
expect(onStart).toHaveBeenCalledTimes(1);
});
it("calls onDefer with duration when Defer clicked", async () => {
const user = userEvent.setup();
const onDefer = vi.fn();
const item = makeFocusItem();
render(
);
await user.click(screen.getByRole("button", { name: /defer/i }));
expect(onDefer).toHaveBeenCalledWith("1h");
});
it("calls onSkip when Skip clicked", async () => {
const user = userEvent.setup();
const onSkip = vi.fn();
const item = makeFocusItem();
render(
);
await user.click(screen.getByRole("button", { name: /skip/i }));
expect(onSkip).toHaveBeenCalledTimes(1);
});
it("calls onOpenFull when full window link clicked", async () => {
const user = userEvent.setup();
const onOpenFull = vi.fn();
render(
);
await user.click(screen.getByText(/full window/i));
expect(onOpenFull).toHaveBeenCalledTimes(1);
});
});
describe("relative time", () => {
beforeEach(() => {
vi.useFakeTimers();
vi.setSystemTime(new Date("2026-02-26T12:00:00Z"));
});
afterEach(() => {
vi.useRealTimers();
});
it("shows age for items", () => {
const item = makeFocusItem({
updatedAt: new Date("2026-02-24T12:00:00Z").toISOString(), // 2 days ago
});
render();
expect(screen.getByText(/2d/)).toBeInTheDocument();
});
});
});