agent-ecosystem/test/main/services/team/TeamKanbanManager.test.ts
iliya 3c1ef54ce2 feat: enhance team member management with color coding and improved prompts
- Added member color assignment using a new utility function for better visual representation in the UI.
- Updated team member prompts to encourage brief introductions, aligning with project guidelines.
- Introduced a draft persistence mechanism for message and task creation dialogs to enhance user experience.
- Refactored team configuration handling to support new member structures and improve data integrity.

This update aims to streamline team interactions and improve the overall user experience in team management features.
2026-02-22 23:36:11 +02:00

135 lines
4 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from 'vitest';
const hoisted = vi.hoisted(() => {
const files = new Map<string, string>();
// Normalize path separators so tests pass on Windows (backslash → forward slash)
const norm = (p: string): string => p.replace(/\\/g, '/');
const readFile = vi.fn(async (filePath: string) => {
const data = files.get(norm(filePath));
if (data === undefined) {
const error = new Error('ENOENT') as NodeJS.ErrnoException;
error.code = 'ENOENT';
throw error;
}
return data;
});
const atomicWrite = vi.fn(async (filePath: string, data: string) => {
files.set(norm(filePath), data);
});
return { files, readFile, atomicWrite };
});
vi.mock('fs', () => ({
promises: {
readFile: hoisted.readFile,
},
}));
vi.mock('../../../../src/main/utils/pathDecoder', () => ({
getTeamsBasePath: () => '/mock/teams',
}));
vi.mock('../../../../src/main/services/team/atomicWrite', () => ({
atomicWriteAsync: hoisted.atomicWrite,
}));
import { TeamKanbanManager } from '../../../../src/main/services/team/TeamKanbanManager';
describe('TeamKanbanManager', () => {
const manager = new TeamKanbanManager();
const statePath = '/mock/teams/my-team/kanban-state.json';
beforeEach(() => {
hoisted.files.clear();
hoisted.readFile.mockClear();
hoisted.atomicWrite.mockClear();
});
it('returns default state on ENOENT', async () => {
const result = await manager.getState('my-team');
expect(result).toEqual({
teamName: 'my-team',
reviewers: [],
tasks: {},
});
});
it('returns default state on corrupted JSON', async () => {
hoisted.files.set(statePath, '{bad-json');
const result = await manager.getState('my-team');
expect(result).toEqual({
teamName: 'my-team',
reviewers: [],
tasks: {},
});
});
it('writes review state with movedAt on set_column', async () => {
await manager.updateTask('my-team', '12', { op: 'set_column', column: 'review' });
const persisted = JSON.parse(hoisted.files.get(statePath) ?? '{}') as {
tasks?: Record<string, { column: string; movedAt: string; reviewStatus?: string }>;
};
expect(persisted.tasks?.['12']?.column).toBe('review');
expect(persisted.tasks?.['12']?.reviewStatus).toBe('pending');
expect(typeof persisted.tasks?.['12']?.movedAt).toBe('string');
expect(hoisted.atomicWrite).toHaveBeenCalledTimes(1);
});
it('removes task state on remove', async () => {
hoisted.files.set(
statePath,
JSON.stringify({
teamName: 'my-team',
reviewers: [],
tasks: {
'12': { column: 'review', movedAt: '2026-01-01T00:00:00.000Z' },
},
})
);
await manager.updateTask('my-team', '12', { op: 'remove' });
const persisted = JSON.parse(hoisted.files.get(statePath) ?? '{}') as {
tasks?: Record<string, unknown>;
};
expect(persisted.tasks).toEqual({});
});
it('garbageCollect removes only stale tasks', async () => {
hoisted.files.set(
statePath,
JSON.stringify({
teamName: 'my-team',
reviewers: [],
tasks: {
'12': { column: 'review', movedAt: '2026-01-01T00:00:00.000Z' },
'13': { column: 'approved', movedAt: '2026-01-01T00:00:00.000Z' },
},
})
);
await manager.garbageCollect('my-team', new Set(['12']));
const persisted = JSON.parse(hoisted.files.get(statePath) ?? '{}') as {
tasks?: Record<string, unknown>;
};
expect(Object.keys(persisted.tasks ?? {})).toEqual(['12']);
});
it('garbageCollect does not write when nothing to remove', async () => {
hoisted.files.set(
statePath,
JSON.stringify({
teamName: 'my-team',
reviewers: [],
tasks: {
'12': { column: 'review', movedAt: '2026-01-01T00:00:00.000Z' },
},
})
);
await manager.garbageCollect('my-team', new Set(['12']));
expect(hoisted.atomicWrite).not.toHaveBeenCalled();
});
});