- Added architectural plan and iteration plan for the in-app project editor. - Introduced new components for the editor, including CodeEditorOverlay, FileTreePanel, and EditorTabsPanel. - Established state management using Zustand for editor state persistence. - Implemented IPC channels for file operations and editor functionality. - Enhanced TeamDetailView with a button to open the editor overlay. - Conducted reuse analysis for existing components to optimize codebase integration.
133 lines
4.2 KiB
TypeScript
133 lines
4.2 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
import { create } from 'zustand';
|
|
|
|
import { createTeamSlice } from '../../../src/renderer/store/slices/teamSlice';
|
|
|
|
const hoisted = vi.hoisted(() => ({
|
|
list: vi.fn(),
|
|
getData: vi.fn(),
|
|
createTeam: vi.fn(),
|
|
getProvisioningStatus: vi.fn(),
|
|
cancelProvisioning: vi.fn(),
|
|
sendMessage: vi.fn(),
|
|
requestReview: vi.fn(),
|
|
updateKanban: vi.fn(),
|
|
onProvisioningProgress: vi.fn(() => () => undefined),
|
|
}));
|
|
|
|
vi.mock('@renderer/api', () => ({
|
|
api: {
|
|
teams: {
|
|
list: hoisted.list,
|
|
getData: hoisted.getData,
|
|
createTeam: hoisted.createTeam,
|
|
getProvisioningStatus: hoisted.getProvisioningStatus,
|
|
cancelProvisioning: hoisted.cancelProvisioning,
|
|
sendMessage: hoisted.sendMessage,
|
|
requestReview: hoisted.requestReview,
|
|
updateKanban: hoisted.updateKanban,
|
|
onProvisioningProgress: hoisted.onProvisioningProgress,
|
|
},
|
|
},
|
|
}));
|
|
|
|
vi.mock('../../../src/renderer/utils/unwrapIpc', async (importOriginal) => {
|
|
const actual = await importOriginal<typeof import('../../../src/renderer/utils/unwrapIpc')>();
|
|
return {
|
|
...actual,
|
|
unwrapIpc: async <T>(_operation: string, fn: () => Promise<T>): Promise<T> => {
|
|
try {
|
|
return await fn();
|
|
} catch (error) {
|
|
const message = error instanceof Error ? error.message : String(error);
|
|
throw new actual.IpcError('mock-op', message, error);
|
|
}
|
|
},
|
|
};
|
|
});
|
|
|
|
function createSliceStore() {
|
|
return create<any>()((set, get, store) => ({
|
|
...createTeamSlice(set as never, get as never, store as never),
|
|
paneLayout: {
|
|
focusedPaneId: 'pane-default',
|
|
panes: [
|
|
{
|
|
id: 'pane-default',
|
|
widthFraction: 1,
|
|
tabs: [],
|
|
activeTabId: null,
|
|
},
|
|
],
|
|
},
|
|
openTab: vi.fn(),
|
|
setActiveTab: vi.fn(),
|
|
getAllPaneTabs: vi.fn(() => []),
|
|
}));
|
|
}
|
|
|
|
describe('teamSlice actions', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
hoisted.list.mockResolvedValue([]);
|
|
hoisted.getData.mockResolvedValue({
|
|
teamName: 'my-team',
|
|
config: { name: 'My Team' },
|
|
tasks: [],
|
|
members: [],
|
|
messages: [],
|
|
kanbanState: { teamName: 'my-team', reviewers: [], tasks: {} },
|
|
});
|
|
hoisted.sendMessage.mockResolvedValue({ deliveredToInbox: true, messageId: 'm1' });
|
|
hoisted.requestReview.mockResolvedValue(undefined);
|
|
hoisted.updateKanban.mockResolvedValue(undefined);
|
|
hoisted.createTeam.mockResolvedValue({ runId: 'run-1' });
|
|
hoisted.getProvisioningStatus.mockResolvedValue({
|
|
runId: 'run-1',
|
|
teamName: 'my-team',
|
|
state: 'spawning',
|
|
message: 'Starting',
|
|
startedAt: new Date().toISOString(),
|
|
updatedAt: new Date().toISOString(),
|
|
});
|
|
hoisted.cancelProvisioning.mockResolvedValue(undefined);
|
|
});
|
|
|
|
it('maps inbox verify failure to user-friendly text', async () => {
|
|
const store = createSliceStore();
|
|
hoisted.sendMessage.mockRejectedValue(new Error('Failed to verify inbox write'));
|
|
|
|
await store.getState().sendTeamMessage('my-team', { member: 'alice', text: 'hello' });
|
|
|
|
expect(store.getState().sendMessageError).toBe(
|
|
'Message was written but not verified (race). Please try again.'
|
|
);
|
|
});
|
|
|
|
it('maps task status verify failure in updateKanban and rethrows', async () => {
|
|
const store = createSliceStore();
|
|
hoisted.updateKanban.mockRejectedValue(new Error('Task status update verification failed: 12'));
|
|
|
|
await expect(
|
|
store.getState().updateKanban('my-team', '12', { op: 'request_changes' })
|
|
).rejects.toThrow('Task status update verification failed: 12');
|
|
|
|
expect(store.getState().reviewActionError).toBe(
|
|
'Failed to update task status (possible agent conflict).'
|
|
);
|
|
});
|
|
|
|
it('maps task status verify failure in requestReview and rethrows', async () => {
|
|
const store = createSliceStore();
|
|
hoisted.requestReview.mockRejectedValue(
|
|
new Error('Task status update verification failed: 22')
|
|
);
|
|
|
|
await expect(store.getState().requestReview('my-team', '22')).rejects.toThrow(
|
|
'Task status update verification failed: 22'
|
|
);
|
|
expect(store.getState().reviewActionError).toBe(
|
|
'Failed to update task status (possible agent conflict).'
|
|
);
|
|
});
|
|
});
|