fix(test): fix 7 test failures in chat-routes and routes-agents suites

Group A (2 failures): resolveProjectChatContext was calling
getOrCreateProjectStore even when no engine existed for the
project. This triggered real FS lookups in tests, causing the
catch to return the default store instead of the engine store.
Fix: only take the engine path when an engine is actually found.

Group B (1 failure): createSSERequest() returned a bare
EventEmitter with no .query property. The refactored handler
reads req.query.projectId at the top, throwing TypeError.
Fix: initialise .query = {} in createSSERequest().

Group C (4 failures): createMockStore() in routes-agents.test.ts
was missing getFusionDir(), which getOrCreateScopedChatStore()
calls to compute the cache key. The resulting TypeError caused
every lookup=resume handler invocation to 500.
Fix: add getFusionDir() to the mock.
This commit is contained in:
Josemi Liebana
2026-05-26 15:58:02 +02:00
parent 8650480622
commit dae167a127
3 changed files with 24 additions and 14 deletions

View File

@@ -10,6 +10,7 @@ import { createCoreMock, createEngineMock } from "../test/mockCoreEngine.js";
function createSSERequest(): Request {
const emitter = new EventEmitter();
emitter.setMaxListeners(50);
(emitter as any).query = {}; // required: routes read req.query.projectId
return emitter as unknown as Request;
}

View File

@@ -219,6 +219,7 @@ function createMockStore(overrides: Partial<TaskStore> = {}): TaskStore {
updatePrInfo: vi.fn().mockResolvedValue(undefined),
updateIssueInfo: vi.fn().mockResolvedValue(undefined),
getRootDir: vi.fn().mockReturnValue("/fake/root"),
getFusionDir: vi.fn().mockReturnValue("/fake/root/.fusion"),
listWorkflowSteps: vi.fn().mockResolvedValue([]),
createWorkflowStep: vi.fn(),
getWorkflowStep: vi.fn(),

View File

@@ -1,7 +1,6 @@
import { AgentStore, ChatStore, type MessageStore, type TaskStore } from "@fusion/core";
import type { ProjectEngineManager } from "@fusion/engine";
import { ChatManager } from "./chat.js";
import { getOrCreateProjectStore } from "./project-store-resolver.js";
const scopedChatStoreCache = new Map<string, ChatStore>();
@@ -38,20 +37,29 @@ export async function resolveProjectChatContext(options: {
};
}
const engine = engineManager?.getEngine(projectId);
try {
const scopedStore = engine?.getTaskStore() ?? await getOrCreateProjectStore(projectId);
const engineChatStore = engine?.getChatStore?.();
return {
store: scopedStore,
chatStore: getOrCreateScopedChatStore(scopedStore, engineChatStore),
};
} catch {
return {
store: defaultStore,
chatStore: getOrCreateScopedChatStore(defaultStore, defaultChatStore),
};
// Only use engine path when an engine is actually found for this project.
if (engineManager) {
const engine = engineManager.getEngine(projectId);
if (engine) {
try {
const scopedStore = engine.getTaskStore?.() ?? defaultStore;
const engineChatStore = engine.getChatStore?.();
return {
store: scopedStore,
chatStore: getOrCreateScopedChatStore(scopedStore, engineChatStore),
};
} catch {
// engine's store not accessible — fall through to default
}
}
}
// No engine for this project — use the default store.
// Route handlers apply projectId filtering at the query level.
return {
store: defaultStore,
chatStore: getOrCreateScopedChatStore(defaultStore, defaultChatStore),
};
}
export async function createProjectScopedChatManager(options: {