Files
makelore/tests/unit/coding-projects-facade.test.ts

103 lines
4.1 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from 'vitest';
const hostApiFetch = vi.hoisted(() => vi.fn());
vi.mock('@/lib/host-api', () => ({ hostApiFetch }));
describe('coding project Host facade', () => {
beforeEach(() => vi.clearAllMocks());
it('uses only the vendor-neutral project metadata routes', async () => {
hostApiFetch
.mockResolvedValueOnce({ projects: [], activeProjectId: null })
.mockResolvedValueOnce({ snapshot: { project: { id: 'project/a' }, config: {} } })
.mockResolvedValueOnce({ conversations: [] })
.mockResolvedValueOnce({ conversation: { id: 'conversation-1' } })
.mockResolvedValueOnce({ conversation: { id: 'conversation-1', title: 'Renamed' } })
.mockResolvedValueOnce({});
const {
createCodingProjectConversation,
getCodingProjectConfig,
listCodingProjectConversations,
listCodingProjects,
patchCodingProjectConversation,
deleteCodingProjectConversation,
} = await import('@/lib/coding-projects');
await listCodingProjects();
await getCodingProjectConfig('project/a');
await listCodingProjectConversations('project/a');
await createCodingProjectConversation({
projectId: 'project/a',
agentId: 'agent-1',
title: '新对话',
});
await patchCodingProjectConversation('conversation/1', { title: 'Renamed', unread: true });
await deleteCodingProjectConversation('conversation/1');
expect(hostApiFetch.mock.calls).toEqual([
['/api/coding/projects'],
['/api/coding/projects/config?projectId=project%2Fa'],
['/api/coding/projects/conversations?projectId=project%2Fa'],
['/api/coding/projects/conversations', {
method: 'POST',
body: JSON.stringify({ projectId: 'project/a', agentId: 'agent-1', title: '新对话' }),
}],
['/api/coding/conversations/conversation%2F1', {
method: 'PATCH',
body: JSON.stringify({ title: 'Renamed', unread: true }),
}],
['/api/coding/conversations/conversation%2F1', { method: 'DELETE' }],
]);
});
it('sends explicit identity choices and a literal independent-copy confirmation', async () => {
hostApiFetch
.mockResolvedValueOnce({ snapshot: { project: { id: 'local-1' }, config: { projectId: 'aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa' }, knowledgeFiles: [] } })
.mockResolvedValueOnce({ snapshot: { project: { id: 'local-1' }, config: { projectId: 'bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb' }, knowledgeFiles: [] } })
.mockResolvedValueOnce({ snapshot: { project: { id: 'local-1' }, config: { projectId: 'cccccccc-cccc-4ccc-8ccc-cccccccccccc' }, knowledgeFiles: [] } });
const {
createCodingProject,
isCanonicalCodingProjectId,
makeCodingProjectIndependentCopy,
resolveCodingProjectIdentity,
} = await import('@/lib/coding-projects');
await createCodingProject({
projectPath: 'C:/projects/new',
projectType: 'custom',
identity: { kind: 'create' },
});
await resolveCodingProjectIdentity('local-1', {
kind: 'bind',
projectId: 'bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb',
});
await makeCodingProjectIndependentCopy('local-1');
expect(isCanonicalCodingProjectId('bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb')).toBe(true);
expect(isCanonicalCodingProjectId('BBBBBBBB-BBBB-4BBB-8BBB-BBBBBBBBBBBB')).toBe(false);
expect(isCanonicalCodingProjectId('not-a-project-id')).toBe(false);
expect(hostApiFetch.mock.calls).toEqual([
['/api/coding/projects/create', {
method: 'POST',
body: JSON.stringify({
projectPath: 'C:/projects/new',
projectType: 'custom',
identity: { kind: 'create' },
}),
}],
['/api/coding/projects/identity', {
method: 'POST',
body: JSON.stringify({
localProjectId: 'local-1',
identity: { kind: 'bind', projectId: 'bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb' },
}),
}],
['/api/coding/projects/identity/independent-copy', {
method: 'POST',
body: JSON.stringify({ localProjectId: 'local-1', confirmed: true }),
}],
]);
});
});