Files
fusion/packages/dashboard/app/components/__tests__/TaskCard.footer-alignment.test.tsx
Fusion (runfusion.ai) 53e0372bc9 test(FN-4986): complete Step 3 — update footer cluster alignment assertions
Fusion-Task-Id: FN-4986
Fusion-Task-Lineage: d7a2c969-f3ea-4f93-bcdb-f86521845fce
2026-05-17 21:34:06 -07:00

169 lines
5.1 KiB
TypeScript

import { describe, it, expect, vi, beforeAll, afterAll } from "vitest";
import { render } from "@testing-library/react";
import type { Task } from "@fusion/core";
import { TaskCard } from "../TaskCard";
import { loadAllAppCss } from "../../test/cssFixture";
vi.mock("lucide-react", () => ({
Link: () => <svg />,
GitBranch: () => <svg />,
Clock: () => <svg />,
Pencil: () => <svg />,
Layers: () => <svg />,
ChevronDown: () => <svg />,
Folder: () => <svg />,
GitPullRequest: () => <svg />,
CircleDot: () => <svg />,
Target: () => <svg />,
Bot: () => <svg />,
Trash2: () => <svg />,
RotateCw: () => <svg />,
Zap: () => <svg />,
}));
vi.mock("../../hooks/useTaskDiffStats", () => ({
useTaskDiffStats: () => ({ stats: null, loading: false }),
}));
vi.mock("../../hooks/useBadgeWebSocket", () => ({
useBadgeWebSocket: () => ({
badgeUpdates: new Map(),
isConnected: true,
subscribeToBadge: vi.fn(),
unsubscribeFromBadge: vi.fn(),
}),
}));
vi.mock("../../hooks/useBatchBadgeFetch", () => ({
getFreshBatchData: vi.fn(() => null),
}));
vi.mock("../../api", () => ({
fetchTaskDetail: vi.fn(),
uploadAttachment: vi.fn(),
fetchMission: vi.fn(),
fetchAgent: vi.fn(),
}));
vi.mock("../../hooks/useConfirm", () => ({
useConfirm: () => ({ confirm: vi.fn(async () => true) }),
}));
const noop = () => {};
function makeTask(): Task {
return {
id: "FN-4598",
title: "Alignment test",
description: "",
column: "in-progress",
steps: [],
dependencies: [],
sourceType: "github_import",
issueInfo: {
owner: "runfusion",
repo: "fusion",
number: 315,
title: "Imported issue",
url: "https://github.com/runfusion/fusion/issues/315",
},
githubTracking: {
enabled: true,
issue: {
owner: "runfusion",
repo: "fusion",
number: 316,
url: "https://github.com/runfusion/fusion/issues/316",
createdAt: new Date().toISOString(),
},
},
retrySummary: { total: 2 },
columnMovedAt: new Date(Date.now() - 60_000).toISOString(),
} as Task;
}
describe("FN-4598 TaskCard footer chip alignment", () => {
let styleEl: HTMLStyleElement;
beforeAll(() => {
styleEl = document.createElement("style");
styleEl.textContent = loadAllAppCss();
document.head.appendChild(styleEl);
});
afterAll(() => {
styleEl.remove();
});
it("keeps footer chips and inner spans vertically centered", () => {
const { container } = render(
<TaskCard task={makeTask()} onOpenDetail={noop} addToast={noop} onOpenDetailWithTab={noop} />,
);
const selectors = [
".card-retry-badge",
".card-time-indicator",
".card-github-tracking-chip",
] as const;
for (const selector of selectors) {
const chip = container.querySelector(selector) as HTMLElement;
expect(chip).toBeTruthy();
const chipStyle = getComputedStyle(chip);
expect(chipStyle.display).toBe("inline-flex");
expect(chipStyle.alignItems).toBe("center");
expect(chipStyle.lineHeight).toBe("1");
const textSpan = chip.querySelector("span") as HTMLElement;
expect(textSpan).toBeTruthy();
const textStyle = getComputedStyle(textSpan);
expect(textStyle.display).toBe("inline-flex");
expect(textStyle.alignItems).toBe("center");
expect(textStyle.lineHeight).toBe("1");
expect(textStyle.transform).toMatch(/translateY\(1px\)|matrix\(1,\s*0,\s*0,\s*1,\s*0,\s*1\)/);
}
});
it("keeps github, retry, and timer as a single right-aligned cluster with token gap", () => {
const { container } = render(
<TaskCard
task={{
...makeTask(),
sourceType: "dashboard_ui",
column: "in-review",
retrySummary: { total: 2 },
executionStartedAt: "2026-05-12T00:00:00.000Z",
updatedAt: "2026-05-12T00:05:00.000Z",
}}
onOpenDetail={noop}
addToast={noop}
onOpenDetailWithTab={noop}
/>,
);
const footerRow = container.querySelector(".card-footer-row") as HTMLElement;
const githubChip = footerRow.querySelector(":scope > .card-github-tracking-chip") as HTMLElement;
const retryChip = footerRow.querySelector(":scope > .card-retry-badge") as HTMLElement;
const timerChip = footerRow.querySelector(":scope > .card-time-indicator") as HTMLElement;
expect(footerRow).toBeTruthy();
expect(githubChip).toBeTruthy();
expect(retryChip).toBeTruthy();
expect(timerChip).toBeTruthy();
const children = Array.from(footerRow.children);
expect(children).toContain(githubChip);
expect(children).toContain(retryChip);
expect(children).toContain(timerChip);
expect(children.indexOf(githubChip)).toBeLessThan(children.indexOf(retryChip));
expect(children.indexOf(retryChip)).toBeLessThan(children.indexOf(timerChip));
expect(getComputedStyle(githubChip).marginLeft).toBe("auto");
expect(getComputedStyle(retryChip).marginLeft).toBe("0px");
expect(getComputedStyle(timerChip).marginLeft).toBe("0px");
const footerStyle = getComputedStyle(footerRow);
expect(footerStyle.gap).toBe("var(--space-sm)");
});
});