feat(FN-5162): merge fusion/fn-5162

This commit is contained in:
gsxdsm
2026-05-19 11:14:49 -07:00
parent d467725c74
commit 71a2ea1954
4 changed files with 129 additions and 1 deletions

View File

@@ -63,7 +63,10 @@
.card-header {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 6px;
row-gap: var(--space-xs);
min-width: 0;
margin-bottom: var(--space-xs);
}
@@ -160,6 +163,10 @@
.card-no-commits-expected-badge {
display: inline-flex;
align-items: center;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 0.625rem;
font-weight: 600;
line-height: 1;
@@ -598,6 +605,10 @@
.card-agent-created-badge {
display: inline-flex;
align-items: center;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
gap: var(--space-xs);
font-size: 0.625rem;
font-weight: 600;

View File

@@ -0,0 +1,114 @@
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { render } from "@testing-library/react";
import { TaskCard } from "../TaskCard";
import type { Task } from "@fusion/core";
import { loadAllAppCss } from "../../test/cssFixture";
vi.mock("lucide-react", () => ({
Link: () => null,
GitBranch: () => null,
Clock: () => null,
Pencil: () => null,
Layers: () => null,
ChevronDown: () => null,
Folder: () => null,
GitPullRequest: () => null,
CircleDot: () => null,
CheckCircle2: () => null,
XCircle: () => null,
Target: () => null,
Bot: () => null,
Trash2: () => null,
RotateCw: () => null,
Zap: () => null,
}));
vi.mock("../ProviderIcon", () => ({
ProviderIcon: () => null,
}));
vi.mock("../PluginSlot", () => ({
PluginSlot: () => null,
}));
vi.mock("../../hooks/useTaskDiffStats", () => ({
useTaskDiffStats: () => ({ stats: null, loading: false }),
}));
const noop = () => {};
function makeTask(overrides: Partial<Task> = {}): Task {
return {
id: "FN-5162",
title: "Wrap this very long task title without letting the badge row overflow the card boundary",
column: "in-progress",
status: "planning" as Task["status"],
steps: [],
dependencies: [],
description: "",
...overrides,
} as Task;
}
describe("TaskCard badge wrapping (FN-5162)", () => {
let cleanupCss: (() => void) | undefined;
let container: HTMLElement;
beforeEach(async () => {
const style = document.createElement("style");
style.textContent = await Promise.resolve(loadAllAppCss());
document.head.appendChild(style);
cleanupCss = () => style.remove();
container = render(
<TaskCard
task={makeTask({
priority: "urgent" as Task["priority"],
executionMode: "fast",
noCommitsExpected: true,
sourceType: "agent_heartbeat",
sourceAgentId: "agent-badge-wrap",
issueInfo: {
owner: "owner",
repo: "repo",
number: 42,
state: "open",
title: "Tracked issue with a long badge label",
url: "https://github.com/owner/repo/issues/42",
} as Task["issueInfo"],
})}
onOpenDetail={noop}
addToast={noop}
/>,
).container;
});
afterEach(() => {
cleanupCss?.();
cleanupCss = undefined;
});
it("wraps the header row and keeps a non-zero row gap", () => {
const header = container.querySelector(".card-header");
expect(header).toBeTruthy();
const styles = getComputedStyle(header!);
expect(styles.flexWrap).toBe("wrap");
expect(styles.rowGap).toMatch(/^(var\(--space-xs\)|(?!0px$)\d+(?:\.\d+)?px)$/);
});
it.each([
".card-status-badge",
".card-priority-badge",
".card-agent-created-badge",
".card-no-commits-expected-badge",
".card-github-badge",
])("applies truncation constraints to %s when rendered", (selector) => {
const badge = container.querySelector(selector);
expect(badge, `${selector} should render for the fixture`).toBeTruthy();
const styles = getComputedStyle(badge as Element);
expect(styles.maxWidth).not.toBe("none");
expect(styles.whiteSpace).toBe("nowrap");
});
});

View File

@@ -1992,6 +1992,9 @@ input[type="range"]:focus-visible {
.card-github-badge {
display: inline-flex;
align-items: center;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
gap: var(--space-xs);
font-size: 0.6875rem;
font-weight: 600;

View File

@@ -12,7 +12,7 @@ const qualityAppTests = [
"app/api/**/*.test.ts",
// Representative workflow/component coverage. Exhaustive modal/view suites
// stay available in the full `dashboard-app` project.
"app/components/__tests__/{ActiveAgentsPanel,ActivityLogModal,AgentMentionPopup,AgentMetricsBar,AgentOnboardingModal,AgentReflectionsTab,AgentTokenStatsPanel,App,AuthTokenRecoveryDialog,Board,board-mobile-view-switch,ChatView,ChatView.autosize,ChatView.chat-input-autosize,ChatView.default-model-icon,ChatView.draft,ChatView.rooms,ChatView.swipe-back,Column,ConfirmDialog,ConversationHistory,DashboardLoader,DevServerView.mobile,DirectoryPicker,DuplicateWarningModal,ErrorBoundary,ExecutorStatusBar,FileBrowser,FileEditor,GitHubBadge,InlineCreateCard,LoginInstructions,MemoryView,MessageComposer,MessageComposer.autosize,MobileNavBar,NewTaskModal,NodeCard,NodeHealthDot,NodeStatusIndicator,PlanningModeModal.autosize,PrChecksList,PrCreateModal,PrCreateModal.layout,ProjectCard,ProjectSelector,ProviderIcon,PrPanel,PrPanel.merge,PrPanel.reviews,QuickChatFAB,ReliabilityView,ResearchView,SecretsView,SettingsModal,SettingsModal.worktrunk,StashRecoveryView,TaskCard,TaskCard.badge-height,TaskChangesTab,TaskComments,TaskDetailModal,TaskDetailModal.github-tracking-header,TaskDetailModal.github-tracking-stale,TaskDetailModal.rebind-banner,TaskDocumentsTab,TaskForm,TaskIdIntegrityBanner,TrackingRepoSelect,WorkflowResultsTab,WorktrunkInstallApprovalDetails}.test.tsx",
"app/components/__tests__/{ActiveAgentsPanel,ActivityLogModal,AgentMentionPopup,AgentMetricsBar,AgentOnboardingModal,AgentReflectionsTab,AgentTokenStatsPanel,App,AuthTokenRecoveryDialog,Board,board-mobile-view-switch,ChatView,ChatView.autosize,ChatView.chat-input-autosize,ChatView.default-model-icon,ChatView.draft,ChatView.rooms,ChatView.swipe-back,Column,ConfirmDialog,ConversationHistory,DashboardLoader,DevServerView.mobile,DirectoryPicker,DuplicateWarningModal,ErrorBoundary,ExecutorStatusBar,FileBrowser,FileEditor,GitHubBadge,InlineCreateCard,LoginInstructions,MemoryView,MessageComposer,MessageComposer.autosize,MobileNavBar,NewTaskModal,NodeCard,NodeHealthDot,NodeStatusIndicator,PlanningModeModal.autosize,PrChecksList,PrCreateModal,PrCreateModal.layout,ProjectCard,ProjectSelector,ProviderIcon,PrPanel,PrPanel.merge,PrPanel.reviews,QuickChatFAB,ReliabilityView,ResearchView,SecretsView,SettingsModal,SettingsModal.worktrunk,StashRecoveryView,TaskCard,TaskCard.badge-height,TaskCard.badge-wrap,TaskChangesTab,TaskComments,TaskDetailModal,TaskDetailModal.github-tracking-header,TaskDetailModal.github-tracking-stale,TaskDetailModal.rebind-banner,TaskDocumentsTab,TaskForm,TaskIdIntegrityBanner,TrackingRepoSelect,WorkflowResultsTab,WorktrunkInstallApprovalDetails}.test.tsx",
// Hooks and utilities are fast, user-visible state/formatting behavior.
"app/context/**/*.test.tsx",
"app/hooks/__tests__/{useAgents,useAgentLogs,useAppSettings,useAuthOnboarding,useConfirm,useCurrentProject,useNodes,useNodeSettingsSync,useProjects,useQuickChat,useTasks,useTerminalSessions,useTheme,useToast,useUsageData,useViewState}.test.{ts,tsx}",