agent-ecosystem/test/renderer/features/agent-graph/collapseOverflowStacks.test.ts

91 lines
3 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import {
collapseOverflowStacks,
collapseOverflowStacksWithMeta,
} from '@features/agent-graph/core/domain/collapseOverflowStacks';
import type { GraphNode } from '@claude-teams/agent-graph';
function makeTaskNode(taskId: string, ownerName: string | null = 'alice'): GraphNode {
return {
id: `task:my-team:${taskId}`,
kind: 'task',
label: `#${taskId}`,
displayId: `#${taskId}`,
sublabel: `Task ${taskId}`,
state: 'waiting',
taskStatus: 'pending',
reviewState: 'none',
ownerId: ownerName ? `member:my-team:${ownerName}` : null,
domainRef: { kind: 'task', teamName: 'my-team', taskId },
};
}
describe('collapseOverflowStacks', () => {
it('keeps all tasks visible when the column fits within the max row count', () => {
const nodes = Array.from({ length: 6 }, (_, index) => makeTaskNode(`task-${index + 1}`));
const result = collapseOverflowStacks(nodes, 'my-team', 6);
expect(result).toHaveLength(6);
expect(result.every((node) => !node.isOverflowStack)).toBe(true);
});
it('replaces the hidden tail with a single overflow stack node while preserving visible order', () => {
const nodes = Array.from({ length: 7 }, (_, index) => makeTaskNode(`task-${index + 1}`));
const result = collapseOverflowStacks(nodes, 'my-team', 6);
expect(result).toHaveLength(6);
expect(result.slice(0, 5).map((node) => node.domainRef.kind === 'task' && node.domainRef.taskId)).toEqual([
'task-1',
'task-2',
'task-3',
'task-4',
'task-5',
]);
expect(result[5]).toMatchObject({
isOverflowStack: true,
overflowCount: 2,
overflowTaskIds: ['task-6', 'task-7'],
domainRef: {
kind: 'task_overflow',
teamName: 'my-team',
ownerMemberName: 'alice',
columnKey: 'todo',
},
});
});
it('applies the same stack rules to unassigned task columns', () => {
const nodes = Array.from({ length: 7 }, (_, index) => makeTaskNode(`task-${index + 1}`, null));
const result = collapseOverflowStacks(nodes, 'my-team', 6);
const stack = result.find((node) => node.isOverflowStack);
expect(stack).toMatchObject({
overflowCount: 2,
overflowTaskIds: ['task-6', 'task-7'],
ownerId: null,
domainRef: {
kind: 'task_overflow',
teamName: 'my-team',
ownerMemberName: null,
columnKey: 'todo',
},
});
});
it('returns a visible-node mapping for hidden tasks behind the stack', () => {
const nodes = Array.from({ length: 7 }, (_, index) => makeTaskNode(`task-${index + 1}`));
const result = collapseOverflowStacksWithMeta(nodes, 'my-team', 6);
const stackNode = result.visibleNodes.find((node) => node.isOverflowStack);
expect(stackNode).toBeDefined();
expect(result.visibleNodeIdByTaskId.get('task-1')).toBe('task:my-team:task-1');
expect(result.visibleNodeIdByTaskId.get('task-6')).toBe(stackNode?.id);
expect(result.visibleNodeIdByTaskId.get('task-7')).toBe(stackNode?.id);
});
});