feat(FN-4370): complete Step 1 — fix badge null-merge semantics
Fusion-Task-Id: FN-4370 Fusion-Task-Lineage: c18188d5-c478-4233-943f-943b0125b271
This commit is contained in:
@@ -31,6 +31,22 @@ vi.mock("../../hooks/useTaskDiffStats", () => ({
|
||||
useTaskDiffStats: (...args: any[]) => useTaskDiffStatsMock(...args),
|
||||
}));
|
||||
|
||||
const badgeUpdatesMock = new Map<string, any>();
|
||||
const subscribeToBadgeMock = vi.fn();
|
||||
const unsubscribeFromBadgeMock = vi.fn();
|
||||
vi.mock("../../hooks/useBadgeWebSocket", () => ({
|
||||
useBadgeWebSocket: () => ({
|
||||
badgeUpdates: badgeUpdatesMock,
|
||||
isConnected: true,
|
||||
subscribeToBadge: subscribeToBadgeMock,
|
||||
unsubscribeFromBadge: unsubscribeFromBadgeMock,
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock("../../hooks/useBatchBadgeFetch", () => ({
|
||||
getFreshBatchData: vi.fn(() => null),
|
||||
}));
|
||||
|
||||
// Mock the api module
|
||||
vi.mock("../../api", () => ({
|
||||
fetchTaskDetail: vi.fn(),
|
||||
@@ -90,6 +106,9 @@ const highFanout = {
|
||||
afterEach(() => {
|
||||
vi.useRealTimers();
|
||||
useTaskDiffStatsMock.mockReturnValue({ stats: null, loading: false });
|
||||
badgeUpdatesMock.clear();
|
||||
subscribeToBadgeMock.mockReset();
|
||||
unsubscribeFromBadgeMock.mockReset();
|
||||
});
|
||||
|
||||
describe("TaskCard", () => {
|
||||
@@ -279,6 +298,31 @@ describe("TaskCard", () => {
|
||||
expect(onOpenDetail).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("renders GitHub badge from live websocket data even when task payload has no badge fields", () => {
|
||||
badgeUpdatesMock.set("default:FN-001", {
|
||||
prInfo: {
|
||||
url: "https://github.com/owner/repo/pull/77",
|
||||
number: 77,
|
||||
status: "open",
|
||||
title: "Live PR",
|
||||
headBranch: "feature/live",
|
||||
baseBranch: "main",
|
||||
commentCount: 0,
|
||||
},
|
||||
timestamp: "2026-05-13T12:00:00.000Z",
|
||||
});
|
||||
|
||||
render(
|
||||
<TaskCard
|
||||
task={makeTask({ column: "in-review", prInfo: undefined, issueInfo: undefined })}
|
||||
onOpenDetail={noop}
|
||||
addToast={noop}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(screen.getByRole("link", { name: "#77" })).toBeDefined();
|
||||
});
|
||||
|
||||
it("clicking issue badge text does not open the task detail modal", () => {
|
||||
const onOpenDetail = vi.fn();
|
||||
render(
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { pickPreferredBadge } from "../TaskCardBadge";
|
||||
|
||||
describe("pickPreferredBadge", () => {
|
||||
const taskValue = { number: 1, lastCheckedAt: "2026-05-13T10:00:00.000Z" };
|
||||
const liveValue = { number: 2, lastCheckedAt: "2026-05-13T11:00:00.000Z" };
|
||||
|
||||
it("returns undefined when both values are missing", () => {
|
||||
expect(pickPreferredBadge(undefined, undefined, undefined, undefined)).toBeUndefined();
|
||||
});
|
||||
|
||||
it("returns undefined when live is null and task is missing", () => {
|
||||
expect(pickPreferredBadge(null, "2026-05-13T12:00:00.000Z", undefined, undefined)).toBeUndefined();
|
||||
});
|
||||
|
||||
it("keeps task value when live is null", () => {
|
||||
expect(
|
||||
pickPreferredBadge(null, "2026-05-13T12:00:00.000Z", taskValue, "2026-05-13T10:00:00.000Z"),
|
||||
).toEqual(taskValue);
|
||||
});
|
||||
|
||||
it("prefers live when newer", () => {
|
||||
expect(
|
||||
pickPreferredBadge(liveValue, "2026-05-13T12:00:00.000Z", taskValue, "2026-05-13T10:00:00.000Z"),
|
||||
).toEqual(liveValue);
|
||||
});
|
||||
|
||||
it("prefers task when newer", () => {
|
||||
expect(
|
||||
pickPreferredBadge(liveValue, "2026-05-13T10:00:00.000Z", taskValue, "2026-05-13T12:00:00.000Z"),
|
||||
).toEqual(taskValue);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user