fix(coding): scope metadata updates by project
This commit is contained in:
@@ -69,6 +69,16 @@ function conversation(id: string, agentId: string): CodingConversationMetadata {
|
||||
};
|
||||
}
|
||||
|
||||
function deferred<T>() {
|
||||
let resolve!: (value: T) => void;
|
||||
let reject!: (reason?: unknown) => void;
|
||||
const promise = new Promise<T>((resolvePromise, rejectPromise) => {
|
||||
resolve = resolvePromise;
|
||||
reject = rejectPromise;
|
||||
});
|
||||
return { promise, resolve, reject };
|
||||
}
|
||||
|
||||
describe('coding workspace store', () => {
|
||||
it('loads local project metadata and selects the pinned Agent without touching runtime APIs', async () => {
|
||||
const listProjects = vi.fn(async () => ({ projects: [project], activeProjectId: project.id }));
|
||||
@@ -156,4 +166,78 @@ describe('coding workspace store', () => {
|
||||
second,
|
||||
]);
|
||||
});
|
||||
|
||||
it('does not write an old project metadata result into the newly active project', async () => {
|
||||
const secondProject = { ...project, id: 'project-2', name: 'Second project' };
|
||||
const firstConversation = conversation('conversation-a', 'agent-a');
|
||||
const secondConversation = conversation('conversation-b', 'agent-b');
|
||||
const patchFlight = deferred<CodingConversationMetadata>();
|
||||
let activeProject = project;
|
||||
const store = createCodingWorkspaceStore({
|
||||
listProjects: vi.fn(async () => ({
|
||||
projects: [project, secondProject],
|
||||
activeProjectId: activeProject.id,
|
||||
})),
|
||||
getConfig: vi.fn(async (projectId: string) => (
|
||||
projectId === project.id
|
||||
? { project, config: config([agent('agent-a')]) }
|
||||
: { project: secondProject, config: config([agent('agent-b')]) }
|
||||
)),
|
||||
listConversations: vi.fn(async (projectId: string) => (
|
||||
projectId === project.id ? [firstConversation] : [secondConversation]
|
||||
)),
|
||||
createConversation: vi.fn(),
|
||||
patchConversation: vi.fn(() => patchFlight.promise),
|
||||
});
|
||||
await store.getState().load();
|
||||
|
||||
const pendingPatch = store.getState().patchConversation(firstConversation.id, { title: 'Old project title' });
|
||||
activeProject = secondProject;
|
||||
await store.getState().load();
|
||||
patchFlight.resolve({ ...firstConversation, title: 'Old project title' });
|
||||
await pendingPatch;
|
||||
|
||||
expect(store.getState()).toMatchObject({
|
||||
activeProjectId: secondProject.id,
|
||||
conversations: [secondConversation],
|
||||
});
|
||||
});
|
||||
|
||||
it('keeps a metadata rejection on its source project and Conversation', async () => {
|
||||
const secondProject = { ...project, id: 'project-2', name: 'Second project' };
|
||||
const firstConversation = conversation('conversation-a', 'agent-a');
|
||||
const secondConversation = conversation('conversation-b', 'agent-b');
|
||||
const patchFlight = deferred<CodingConversationMetadata>();
|
||||
let activeProject = project;
|
||||
const store = createCodingWorkspaceStore({
|
||||
listProjects: vi.fn(async () => ({
|
||||
projects: [project, secondProject],
|
||||
activeProjectId: activeProject.id,
|
||||
})),
|
||||
getConfig: vi.fn(async (projectId: string) => (
|
||||
projectId === project.id
|
||||
? { project, config: config([agent('agent-a')]) }
|
||||
: { project: secondProject, config: config([agent('agent-b')]) }
|
||||
)),
|
||||
listConversations: vi.fn(async (projectId: string) => (
|
||||
projectId === project.id ? [firstConversation] : [secondConversation]
|
||||
)),
|
||||
createConversation: vi.fn(),
|
||||
patchConversation: vi.fn(() => patchFlight.promise),
|
||||
});
|
||||
await store.getState().load();
|
||||
|
||||
const pendingPatch = store.getState().patchConversation(firstConversation.id, { title: 'Rejected title' });
|
||||
const rejection = expect(pendingPatch).rejects.toThrow('metadata rejected');
|
||||
activeProject = secondProject;
|
||||
await store.getState().load();
|
||||
patchFlight.reject(new Error('metadata rejected'));
|
||||
await rejection;
|
||||
|
||||
expect(store.getState().error).toBeNull();
|
||||
expect(store.getState().conversationErrorsByProjectId).toEqual({
|
||||
[project.id]: { [firstConversation.id]: 'metadata rejected' },
|
||||
});
|
||||
expect(store.getState().conversationErrorsByProjectId[secondProject.id]).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user