refactor(server/tests): clear 146 type-aware lint errors in session tests (T1.a) (#753)
Replace `as unknown as SessionOptions["X"]` call-site casts with typed stub helpers from a new `test-utils/session-stubs.ts` module. Unsafe assertions are now contained to that single infrastructure file, keeping all call sites in the two fully-fixed test files clean. Files fully fixed (typeAware: true → 0 errors): - session.workspaces.test.ts: 119 → 0 - session.test.ts: 27 → 0 Helpers added in session-stubs.ts: - asSessionLogger / asAgentManager / asAgentStorage / asDownloadTokenStore / asPushTokenStore / asChatService / asScheduleService / asLoopService / asCheckoutDiffManager / asDaemonConfigStore / asTerminalManager / asGitHubService / asWorkspaceGitService / asScriptRouteStore / asWorkspaceScriptRuntimeStore - asSessionInternals<T> for private session access - filterByType / findByType message helpers - createProviderSnapshotManagerStub returning typed spy refs
This commit is contained in:
@@ -32,6 +32,21 @@ import type {
|
|||||||
TurnDetectionProvider,
|
TurnDetectionProvider,
|
||||||
TurnDetectionSession,
|
TurnDetectionSession,
|
||||||
} from "./speech/turn-detection-provider.js";
|
} from "./speech/turn-detection-provider.js";
|
||||||
|
import {
|
||||||
|
asSessionInternals as asSessionInternalsHelper,
|
||||||
|
asAgentManager,
|
||||||
|
asAgentStorage,
|
||||||
|
asDownloadTokenStore,
|
||||||
|
asPushTokenStore,
|
||||||
|
asChatService,
|
||||||
|
asScheduleService,
|
||||||
|
asLoopService,
|
||||||
|
asCheckoutDiffManager,
|
||||||
|
asGitHubService,
|
||||||
|
asWorkspaceGitService,
|
||||||
|
asDaemonConfigStore,
|
||||||
|
createProviderSnapshotManagerStub,
|
||||||
|
} from "./test-utils/session-stubs.js";
|
||||||
|
|
||||||
interface SessionHandlerInternals {
|
interface SessionHandlerInternals {
|
||||||
startVoiceTurnController(): Promise<void>;
|
startVoiceTurnController(): Promise<void>;
|
||||||
@@ -64,10 +79,14 @@ interface SessionHandlerInternals {
|
|||||||
handleStashPopRequest(params: unknown): Promise<unknown>;
|
handleStashPopRequest(params: unknown): Promise<unknown>;
|
||||||
createPaseoWorktree(params: unknown): Promise<unknown>;
|
createPaseoWorktree(params: unknown): Promise<unknown>;
|
||||||
handleStartWorkspaceScriptRequest(params: unknown): Promise<unknown>;
|
handleStartWorkspaceScriptRequest(params: unknown): Promise<unknown>;
|
||||||
|
getProviderRegistry(): unknown;
|
||||||
|
sttManager: {
|
||||||
|
transcribe(audio: Buffer, format: string): Promise<unknown>;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function asSessionInternals(session: Session): SessionHandlerInternals {
|
function asSessionInternals(session: Session): SessionHandlerInternals {
|
||||||
return session as unknown as SessionHandlerInternals;
|
return asSessionInternalsHelper<SessionHandlerInternals>(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createBinaryMessageHandler(
|
function createBinaryMessageHandler(
|
||||||
@@ -250,9 +269,9 @@ interface SessionForTestOptions {
|
|||||||
};
|
};
|
||||||
workspaceRegistry?: { get: ReturnType<typeof vi.fn> };
|
workspaceRegistry?: { get: ReturnType<typeof vi.fn> };
|
||||||
projectRegistry?: Partial<SessionOptions["projectRegistry"]>;
|
projectRegistry?: Partial<SessionOptions["projectRegistry"]>;
|
||||||
terminalManager?: unknown;
|
terminalManager?: SessionOptions["terminalManager"];
|
||||||
scriptRouteStore?: unknown;
|
scriptRouteStore?: SessionOptions["scriptRouteStore"];
|
||||||
scriptRuntimeStore?: unknown;
|
scriptRuntimeStore?: SessionOptions["scriptRuntimeStore"];
|
||||||
getDaemonTcpPort?: () => number | null;
|
getDaemonTcpPort?: () => number | null;
|
||||||
getDaemonTcpHost?: () => string | null;
|
getDaemonTcpHost?: () => string | null;
|
||||||
providerSnapshotManager?: ProviderSnapshotManager;
|
providerSnapshotManager?: ProviderSnapshotManager;
|
||||||
@@ -290,17 +309,17 @@ function createSessionForTest(options: SessionForTestOptions = {}): Session {
|
|||||||
onMessage: (message) => messages.push(message),
|
onMessage: (message) => messages.push(message),
|
||||||
onBinaryMessage: createBinaryMessageHandler(options.binaryMessages),
|
onBinaryMessage: createBinaryMessageHandler(options.binaryMessages),
|
||||||
logger,
|
logger,
|
||||||
downloadTokenStore: {} as unknown as SessionOptions["downloadTokenStore"],
|
downloadTokenStore: asDownloadTokenStore(),
|
||||||
pushTokenStore: {} as unknown as SessionOptions["pushTokenStore"],
|
pushTokenStore: asPushTokenStore(),
|
||||||
paseoHome: "/tmp/paseo-home",
|
paseoHome: "/tmp/paseo-home",
|
||||||
agentManager: {
|
agentManager: asAgentManager({
|
||||||
listAgents: vi.fn(() => []),
|
listAgents: vi.fn(() => []),
|
||||||
subscribe: vi.fn(() => () => {}),
|
subscribe: vi.fn(() => () => {}),
|
||||||
} as unknown as SessionOptions["agentManager"],
|
}),
|
||||||
agentStorage: {
|
agentStorage: asAgentStorage({
|
||||||
list: vi.fn().mockResolvedValue([]),
|
list: vi.fn().mockResolvedValue([]),
|
||||||
} as unknown as SessionOptions["agentStorage"],
|
}),
|
||||||
projectRegistry: (options.projectRegistry ?? {
|
projectRegistry: options.projectRegistry ?? {
|
||||||
list: vi.fn().mockResolvedValue([]),
|
list: vi.fn().mockResolvedValue([]),
|
||||||
get: vi.fn(),
|
get: vi.fn(),
|
||||||
upsert: vi.fn(),
|
upsert: vi.fn(),
|
||||||
@@ -308,30 +327,30 @@ function createSessionForTest(options: SessionForTestOptions = {}): Session {
|
|||||||
remove: vi.fn(),
|
remove: vi.fn(),
|
||||||
initialize: vi.fn(),
|
initialize: vi.fn(),
|
||||||
existsOnDisk: vi.fn(),
|
existsOnDisk: vi.fn(),
|
||||||
}) as unknown as SessionOptions["projectRegistry"],
|
},
|
||||||
workspaceRegistry: (options.workspaceRegistry ?? {
|
workspaceRegistry: options.workspaceRegistry ?? {
|
||||||
get: vi.fn(),
|
get: vi.fn(),
|
||||||
list: vi.fn().mockResolvedValue([]),
|
list: vi.fn().mockResolvedValue([]),
|
||||||
}) as unknown as SessionOptions["workspaceRegistry"],
|
},
|
||||||
chatService: {} as unknown as SessionOptions["chatService"],
|
chatService: asChatService(),
|
||||||
scheduleService: {} as unknown as SessionOptions["scheduleService"],
|
scheduleService: asScheduleService(),
|
||||||
loopService: {} as unknown as SessionOptions["loopService"],
|
loopService: asLoopService(),
|
||||||
checkoutDiffManager: checkoutDiffManager as unknown as SessionOptions["checkoutDiffManager"],
|
checkoutDiffManager: asCheckoutDiffManager(checkoutDiffManager),
|
||||||
github: github as unknown as SessionOptions["github"],
|
github: asGitHubService(github),
|
||||||
workspaceGitService: workspaceGitService as unknown as SessionOptions["workspaceGitService"],
|
workspaceGitService: asWorkspaceGitService(workspaceGitService),
|
||||||
daemonConfigStore: {
|
daemonConfigStore: asDaemonConfigStore({
|
||||||
get: vi.fn(() => ({
|
get: vi.fn(() => ({
|
||||||
mcp: { injectIntoAgents: false },
|
mcp: { injectIntoAgents: false },
|
||||||
providers: {},
|
providers: {},
|
||||||
})),
|
})),
|
||||||
onChange: vi.fn(() => () => {}),
|
onChange: vi.fn(() => () => {}),
|
||||||
} as unknown as SessionOptions["daemonConfigStore"],
|
}),
|
||||||
stt: options.stt ?? null,
|
stt: options.stt ?? null,
|
||||||
tts: null,
|
tts: null,
|
||||||
terminalManager: (options.terminalManager ?? null) as SessionOptions["terminalManager"],
|
terminalManager: options.terminalManager ?? null,
|
||||||
providerSnapshotManager: options.providerSnapshotManager,
|
providerSnapshotManager: options.providerSnapshotManager,
|
||||||
scriptRouteStore: options.scriptRouteStore as SessionOptions["scriptRouteStore"],
|
scriptRouteStore: options.scriptRouteStore,
|
||||||
scriptRuntimeStore: options.scriptRuntimeStore as SessionOptions["scriptRuntimeStore"],
|
scriptRuntimeStore: options.scriptRuntimeStore,
|
||||||
getDaemonTcpPort: options.getDaemonTcpPort,
|
getDaemonTcpPort: options.getDaemonTcpPort,
|
||||||
getDaemonTcpHost: options.getDaemonTcpHost,
|
getDaemonTcpHost: options.getDaemonTcpHost,
|
||||||
voice: options.voice,
|
voice: options.voice,
|
||||||
@@ -399,16 +418,7 @@ function createVoiceSessionHarness() {
|
|||||||
const sendAgentMessage = vi
|
const sendAgentMessage = vi
|
||||||
.spyOn(internals, "handleSendAgentMessage")
|
.spyOn(internals, "handleSendAgentMessage")
|
||||||
.mockResolvedValue({ ok: true });
|
.mockResolvedValue({ ok: true });
|
||||||
const transcribe = vi.spyOn(
|
const transcribe = vi.spyOn(asSessionInternals(session).sttManager, "transcribe");
|
||||||
(
|
|
||||||
session as unknown as {
|
|
||||||
sttManager: {
|
|
||||||
transcribe(audio: Buffer, format: string): Promise<unknown>;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
).sttManager,
|
|
||||||
"transcribe",
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
session,
|
session,
|
||||||
@@ -906,20 +916,6 @@ function createWorkspaceGitSnapshot(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function createProviderSnapshotManagerStub(): ProviderSnapshotManager {
|
|
||||||
const stub = {
|
|
||||||
getSnapshot: vi.fn(() => []),
|
|
||||||
refreshSnapshotForCwd: vi.fn(async () => {}),
|
|
||||||
refreshSettingsSnapshot: vi.fn(async () => {}),
|
|
||||||
warmUpSnapshotForCwd: vi.fn(async () => {}),
|
|
||||||
on: vi.fn(),
|
|
||||||
off: vi.fn(),
|
|
||||||
};
|
|
||||||
stub.on.mockImplementation(() => stub);
|
|
||||||
stub.off.mockImplementation(() => stub);
|
|
||||||
return stub as unknown as ProviderSnapshotManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
});
|
});
|
||||||
@@ -1039,7 +1035,11 @@ describe("session PR status payload normalization", () => {
|
|||||||
|
|
||||||
describe("session provider refresh cwd routing", () => {
|
describe("session provider refresh cwd routing", () => {
|
||||||
test("routes no-cwd provider snapshot refreshes through settings refresh", async () => {
|
test("routes no-cwd provider snapshot refreshes through settings refresh", async () => {
|
||||||
const providerSnapshotManager = createProviderSnapshotManagerStub();
|
const {
|
||||||
|
manager: providerSnapshotManager,
|
||||||
|
refreshSettingsSnapshot,
|
||||||
|
refreshSnapshotForCwd,
|
||||||
|
} = createProviderSnapshotManagerStub();
|
||||||
const session = createSessionForTest({ providerSnapshotManager });
|
const session = createSessionForTest({ providerSnapshotManager });
|
||||||
|
|
||||||
await session.handleMessage({
|
await session.handleMessage({
|
||||||
@@ -1048,14 +1048,18 @@ describe("session provider refresh cwd routing", () => {
|
|||||||
requestId: "refresh-settings",
|
requestId: "refresh-settings",
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(providerSnapshotManager.refreshSettingsSnapshot).toHaveBeenCalledWith({
|
expect(refreshSettingsSnapshot).toHaveBeenCalledWith({
|
||||||
providers: ["codex"],
|
providers: ["codex"],
|
||||||
});
|
});
|
||||||
expect(providerSnapshotManager.refreshSnapshotForCwd).not.toHaveBeenCalled();
|
expect(refreshSnapshotForCwd).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("routes cwd provider snapshot refreshes through workspace refresh", async () => {
|
test("routes cwd provider snapshot refreshes through workspace refresh", async () => {
|
||||||
const providerSnapshotManager = createProviderSnapshotManagerStub();
|
const {
|
||||||
|
manager: providerSnapshotManager,
|
||||||
|
refreshSnapshotForCwd,
|
||||||
|
refreshSettingsSnapshot,
|
||||||
|
} = createProviderSnapshotManagerStub();
|
||||||
const session = createSessionForTest({ providerSnapshotManager });
|
const session = createSessionForTest({ providerSnapshotManager });
|
||||||
|
|
||||||
await session.handleMessage({
|
await session.handleMessage({
|
||||||
@@ -1065,11 +1069,11 @@ describe("session provider refresh cwd routing", () => {
|
|||||||
requestId: "refresh-workspace",
|
requestId: "refresh-workspace",
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(providerSnapshotManager.refreshSnapshotForCwd).toHaveBeenCalledWith({
|
expect(refreshSnapshotForCwd).toHaveBeenCalledWith({
|
||||||
cwd: "/tmp/workspace-refresh",
|
cwd: "/tmp/workspace-refresh",
|
||||||
providers: ["codex"],
|
providers: ["codex"],
|
||||||
});
|
});
|
||||||
expect(providerSnapshotManager.refreshSettingsSnapshot).not.toHaveBeenCalled();
|
expect(refreshSettingsSnapshot).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("normalizes legacy model and mode list requests without cwd to home", async () => {
|
test("normalizes legacy model and mode list requests without cwd to home", async () => {
|
||||||
@@ -1077,7 +1081,7 @@ describe("session provider refresh cwd routing", () => {
|
|||||||
const session = createSessionForTest({ messages });
|
const session = createSessionForTest({ messages });
|
||||||
const fetchModels = vi.fn(async () => []);
|
const fetchModels = vi.fn(async () => []);
|
||||||
const fetchModes = vi.fn(async () => []);
|
const fetchModes = vi.fn(async () => []);
|
||||||
(session as unknown as { getProviderRegistry: () => unknown }).getProviderRegistry = () => ({
|
asSessionInternals(session).getProviderRegistry = () => ({
|
||||||
codex: createTestProviderDefinition({
|
codex: createTestProviderDefinition({
|
||||||
fetchModels,
|
fetchModels,
|
||||||
fetchModes,
|
fetchModes,
|
||||||
@@ -1101,7 +1105,8 @@ describe("session provider refresh cwd routing", () => {
|
|||||||
|
|
||||||
test("legacy model list request treats disabled snapshot entries as unavailable without warming", async () => {
|
test("legacy model list request treats disabled snapshot entries as unavailable without warming", async () => {
|
||||||
const messages: unknown[] = [];
|
const messages: unknown[] = [];
|
||||||
const providerSnapshotManager = createProviderSnapshotManagerStub();
|
const { manager: providerSnapshotManager, warmUpSnapshotForCwd } =
|
||||||
|
createProviderSnapshotManagerStub();
|
||||||
providerSnapshotManager.getSnapshot = vi.fn(() => [
|
providerSnapshotManager.getSnapshot = vi.fn(() => [
|
||||||
{
|
{
|
||||||
provider: "codex",
|
provider: "codex",
|
||||||
@@ -1117,7 +1122,7 @@ describe("session provider refresh cwd routing", () => {
|
|||||||
requestId: "models-disabled",
|
requestId: "models-disabled",
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(providerSnapshotManager.warmUpSnapshotForCwd).not.toHaveBeenCalled();
|
expect(warmUpSnapshotForCwd).not.toHaveBeenCalled();
|
||||||
expect(messages).toContainEqual({
|
expect(messages).toContainEqual({
|
||||||
type: "list_provider_models_response",
|
type: "list_provider_models_response",
|
||||||
payload: {
|
payload: {
|
||||||
@@ -1131,7 +1136,8 @@ describe("session provider refresh cwd routing", () => {
|
|||||||
|
|
||||||
test("legacy mode list request treats disabled snapshot entries as unavailable without warming", async () => {
|
test("legacy mode list request treats disabled snapshot entries as unavailable without warming", async () => {
|
||||||
const messages: unknown[] = [];
|
const messages: unknown[] = [];
|
||||||
const providerSnapshotManager = createProviderSnapshotManagerStub();
|
const { manager: providerSnapshotManager, warmUpSnapshotForCwd } =
|
||||||
|
createProviderSnapshotManagerStub();
|
||||||
providerSnapshotManager.getSnapshot = vi.fn(() => [
|
providerSnapshotManager.getSnapshot = vi.fn(() => [
|
||||||
{
|
{
|
||||||
provider: "codex",
|
provider: "codex",
|
||||||
@@ -1147,7 +1153,7 @@ describe("session provider refresh cwd routing", () => {
|
|||||||
requestId: "modes-disabled",
|
requestId: "modes-disabled",
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(providerSnapshotManager.warmUpSnapshotForCwd).not.toHaveBeenCalled();
|
expect(warmUpSnapshotForCwd).not.toHaveBeenCalled();
|
||||||
expect(messages).toContainEqual({
|
expect(messages).toContainEqual({
|
||||||
type: "list_provider_modes_response",
|
type: "list_provider_modes_response",
|
||||||
payload: {
|
payload: {
|
||||||
@@ -1175,7 +1181,7 @@ describe("session provider refresh cwd routing", () => {
|
|||||||
label: "Should not fetch",
|
label: "Should not fetch",
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
(session as unknown as { getProviderRegistry: () => unknown }).getProviderRegistry = () => ({
|
asSessionInternals(session).getProviderRegistry = () => ({
|
||||||
codex: createTestProviderDefinition({
|
codex: createTestProviderDefinition({
|
||||||
enabled: false,
|
enabled: false,
|
||||||
fetchModels,
|
fetchModels,
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,145 @@
|
|||||||
|
import { vi } from "vitest";
|
||||||
|
|
||||||
|
import type { ProviderSnapshotEntry } from "../agent/agent-sdk-types.js";
|
||||||
|
import { ProviderSnapshotManager } from "../agent/provider-snapshot-manager.js";
|
||||||
|
import type { SessionOptions } from "../session.js";
|
||||||
|
import type { SessionOutboundMessage } from "../../shared/messages.js";
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Unsafe stub wrappers — as unknown as is ONLY here, never in scope test files
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export function asSessionLogger(stub: object): SessionOptions["logger"] {
|
||||||
|
return stub as unknown as SessionOptions["logger"];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function asAgentManager(stub: object): SessionOptions["agentManager"] {
|
||||||
|
return stub as unknown as SessionOptions["agentManager"];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function asAgentStorage(stub: object): SessionOptions["agentStorage"] {
|
||||||
|
return stub as unknown as SessionOptions["agentStorage"];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function asDownloadTokenStore(): SessionOptions["downloadTokenStore"] {
|
||||||
|
return {} as unknown as SessionOptions["downloadTokenStore"];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function asPushTokenStore(): SessionOptions["pushTokenStore"] {
|
||||||
|
return {} as unknown as SessionOptions["pushTokenStore"];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function asChatService(): SessionOptions["chatService"] {
|
||||||
|
return {} as unknown as SessionOptions["chatService"];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function asScheduleService(): SessionOptions["scheduleService"] {
|
||||||
|
return {} as unknown as SessionOptions["scheduleService"];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function asLoopService(): SessionOptions["loopService"] {
|
||||||
|
return {} as unknown as SessionOptions["loopService"];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function asCheckoutDiffManager(stub: object): SessionOptions["checkoutDiffManager"] {
|
||||||
|
return stub as unknown as SessionOptions["checkoutDiffManager"];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function asDaemonConfigStore(stub: object): SessionOptions["daemonConfigStore"] {
|
||||||
|
return stub as unknown as SessionOptions["daemonConfigStore"];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function asTerminalManager(stub: object): NonNullable<SessionOptions["terminalManager"]> {
|
||||||
|
return stub as unknown as NonNullable<SessionOptions["terminalManager"]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function asGitHubService(stub: object): NonNullable<SessionOptions["github"]> {
|
||||||
|
return stub as unknown as NonNullable<SessionOptions["github"]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function asWorkspaceGitService(stub: object): SessionOptions["workspaceGitService"] {
|
||||||
|
return stub as unknown as SessionOptions["workspaceGitService"];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function asScriptRouteStore(stub: object): SessionOptions["scriptRouteStore"] {
|
||||||
|
return stub as unknown as SessionOptions["scriptRouteStore"];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function asWorkspaceScriptRuntimeStore(stub: object): SessionOptions["scriptRuntimeStore"] {
|
||||||
|
return stub as unknown as SessionOptions["scriptRuntimeStore"];
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Private session access — moves the unsafe cast out of scope files
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export function asSessionInternals<T>(session: unknown): T {
|
||||||
|
return session as unknown as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Type guard for SessionOutboundMessage — avoids casting unknown in test emit overrides
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export function isSessionOutboundMessage(m: unknown): m is SessionOutboundMessage {
|
||||||
|
return typeof m === "object" && m !== null && "type" in m;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Message helpers — type-safe filtering without casts in test files
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export function filterByType<T extends SessionOutboundMessage["type"]>(
|
||||||
|
messages: SessionOutboundMessage[],
|
||||||
|
type: T,
|
||||||
|
): Array<Extract<SessionOutboundMessage, { type: T }>> {
|
||||||
|
return messages.filter((m): m is Extract<SessionOutboundMessage, { type: T }> => m.type === type);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function findByType<T extends SessionOutboundMessage["type"]>(
|
||||||
|
messages: SessionOutboundMessage[],
|
||||||
|
type: T,
|
||||||
|
): Extract<SessionOutboundMessage, { type: T }> | undefined {
|
||||||
|
return messages.find((m): m is Extract<SessionOutboundMessage, { type: T }> => m.type === type);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// ProviderSnapshotManager stub — returns spies separately to avoid
|
||||||
|
// unbound-method lint errors when using expect(spy).toHaveBeenCalled()
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export interface ProviderSnapshotManagerSpies {
|
||||||
|
getSnapshot: ReturnType<typeof vi.fn<[], ProviderSnapshotEntry[]>>;
|
||||||
|
refreshSnapshotForCwd: ReturnType<typeof vi.fn<[], Promise<void>>>;
|
||||||
|
refreshSettingsSnapshot: ReturnType<typeof vi.fn<[], Promise<void>>>;
|
||||||
|
warmUpSnapshotForCwd: ReturnType<typeof vi.fn<[], Promise<void>>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createProviderSnapshotManagerStub(): {
|
||||||
|
manager: ProviderSnapshotManager;
|
||||||
|
} & ProviderSnapshotManagerSpies {
|
||||||
|
const getSnapshot = vi.fn<[], ProviderSnapshotEntry[]>(() => []);
|
||||||
|
const refreshSnapshotForCwd = vi.fn<[], Promise<void>>(async () => {});
|
||||||
|
const refreshSettingsSnapshot = vi.fn<[], Promise<void>>(async () => {});
|
||||||
|
const warmUpSnapshotForCwd = vi.fn<[], Promise<void>>(async () => {});
|
||||||
|
const on = vi.fn();
|
||||||
|
const off = vi.fn();
|
||||||
|
const stub = {
|
||||||
|
getSnapshot,
|
||||||
|
refreshSnapshotForCwd,
|
||||||
|
refreshSettingsSnapshot,
|
||||||
|
warmUpSnapshotForCwd,
|
||||||
|
on,
|
||||||
|
off,
|
||||||
|
};
|
||||||
|
on.mockImplementation(() => stub);
|
||||||
|
off.mockImplementation(() => stub);
|
||||||
|
const manager = stub as unknown as ProviderSnapshotManager;
|
||||||
|
return {
|
||||||
|
manager,
|
||||||
|
getSnapshot,
|
||||||
|
refreshSnapshotForCwd,
|
||||||
|
refreshSettingsSnapshot,
|
||||||
|
warmUpSnapshotForCwd,
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user